0

Minimum size for aura window

Update restore bounds when SetBounds is called in Fullscreen/Maximized mode.

EventGenerator to generate fake events for various mouse operatings.

BUG=none
TEST=added test case for SetBounds in fullscreen/maximized mode. Added ToplevelWindow test that tests various toplevel operations.

Review URL: http://codereview.chromium.org/8273040

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105882 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
oshima@google.com
2011-10-17 19:36:10 +00:00
parent 7bf4a8ef5a
commit 27efc88c2c
13 changed files with 392 additions and 52 deletions

@ -97,6 +97,8 @@
'sources': [
'test/aura_test_base.cc',
'test/aura_test_base.h',
'test/event_generator.cc',
'test/event_generator.h',
'test/run_all_unittests.cc',
'test/test_desktop_delegate.cc',
'test/test_desktop_delegate.h',

@ -0,0 +1,107 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/aura/test/event_generator.h"
#include "ui/aura/desktop.h"
#include "ui/aura/event.h"
namespace {
gfx::Point CenterOfWindowInDesktopCoordinate(aura::Window* window) {
gfx::Point center = window->bounds().CenterPoint();
aura::Desktop* desktop = aura::Desktop::GetInstance();
aura::Window::ConvertPointToWindow(
window->parent(), desktop->window(), &center);
return center;
}
} // namespace
namespace aura {
namespace test {
EventGenerator::EventGenerator() : flags_(0) {
}
EventGenerator::EventGenerator(const gfx::Point& point)
: flags_(0),
current_location_(point) {
}
EventGenerator::EventGenerator(Window* window)
: flags_(0),
current_location_(CenterOfWindowInDesktopCoordinate(window)) {
}
EventGenerator::~EventGenerator() {
}
void EventGenerator::ClickLeftButton() {
PressLeftButton();
ReleaseLeftButton();
}
void EventGenerator::PressLeftButton() {
if ((flags_ & ui::EF_LEFT_BUTTON_DOWN) == 0) {
flags_ |= ui::EF_LEFT_BUTTON_DOWN;
Dispatch(MouseEvent(ui::ET_MOUSE_PRESSED, current_location_, flags_));
}
}
void EventGenerator::ReleaseLeftButton() {
if (flags_ & ui::EF_LEFT_BUTTON_DOWN) {
flags_ ^= ui::EF_LEFT_BUTTON_DOWN;
Dispatch(MouseEvent(ui::ET_MOUSE_RELEASED, current_location_, 0));
}
}
void EventGenerator::MoveMouseTo(const gfx::Point& point) {
if (flags_ & ui::EF_LEFT_BUTTON_DOWN ) {
Dispatch(MouseEvent(
ui::ET_MOUSE_DRAGGED, current_location_.Middle(point), flags_));
Dispatch(MouseEvent(ui::ET_MOUSE_DRAGGED, point, flags_));
} else {
Dispatch(MouseEvent(
ui::ET_MOUSE_MOVED, current_location_.Middle(point), flags_));
Dispatch(MouseEvent(ui::ET_MOUSE_MOVED, point, flags_));
}
current_location_ = point;
}
void EventGenerator::DragMouseTo(const gfx::Point& point) {
PressLeftButton();
MoveMouseTo(point);
ReleaseLeftButton();
}
void EventGenerator::Dispatch(const Event& event) {
switch (event.type()) {
case ui::ET_KEY_PRESSED:
case ui::ET_KEY_RELEASED:
aura::Desktop::GetInstance()->OnKeyEvent(
*static_cast<const KeyEvent*>(&event));
break;
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSEWHEEL:
aura::Desktop::GetInstance()->OnMouseEvent(
*static_cast<const MouseEvent*>(&event));
break;
default:
NOTIMPLEMENTED();
break;
}
}
void EventGenerator::MoveMouseToCenterOf(Window* window) {
MoveMouseTo(CenterOfWindowInDesktopCoordinate(window));
}
} // namespace test
} // namespace aura

@ -0,0 +1,82 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_AURA_TEST_EVENT_GENERATOR_H_
#define UI_AURA_TEST_EVENT_GENERATOR_H_
#pragma once
#include "base/basictypes.h"
#include "ui/gfx/point.h"
namespace aura {
class Event;
class Window;
namespace test {
// EventGenerator is a tool that generates and dispatch events.
// TODO(oshima): Support key events.
class EventGenerator {
public:
// Creates an EventGenerator with the mouse location (0,0).
EventGenerator();
// Creates an EventGenerator with the mouse location at |initial_location|.
explicit EventGenerator(const gfx::Point& initial_location);
// Creates an EventGenerator with the mouse location centered over |window|.
explicit EventGenerator(Window* window);
virtual ~EventGenerator();
const gfx::Point& current_location() const { return current_location_; }
// Generates a left button press event.
void PressLeftButton();
// Generates a left button release event.
void ReleaseLeftButton();
// Generates events to click (press, release) left button.
void ClickLeftButton();
// Generates events to move mouse to be the given |point|.
void MoveMouseTo(const gfx::Point& point);
void MoveMouseTo(int x, int y) {
MoveMouseTo(gfx::Point(x, y));
}
void MoveMouseBy(int x, int y) {
MoveMouseTo(current_location_.Add(gfx::Point(x, y)));
}
// Generates events to drag mouse to given |point|.
void DragMouseTo(const gfx::Point& point);
void DragMouseTo(int x, int y) {
DragMouseTo(gfx::Point(x, y));
}
void DragMouseBy(int dx, int dy) {
DragMouseTo(current_location_.Add(gfx::Point(dx, dy)));
}
// Generates events to move the mouse to the center of the window.
void MoveMouseToCenterOf(Window* window);
private:
// Dispatch the |event| to the Desktop.
void Dispatch(const Event& event);
int flags_;
gfx::Point current_location_;
DISALLOW_COPY_AND_ASSIGN(EventGenerator);
};
} // namespace test
} // namespace aura
#endif // UI_AURA_TEST_EVENT_GENERATOR_H_

@ -130,10 +130,13 @@ bool ToplevelWindowEventFilter::OnMouseEvent(Window* target,
switch (event->type()) {
case ui::ET_MOUSE_MOVED:
window_component_ =
target->delegate()->GetNonClientComponent(event->location());
UpdateWindowComponentForEvent(target, event);
break;
case ui::ET_MOUSE_PRESSED:
// We also update the current window component here because for the
// mouse-drag-release-press case, where the mouse is released and
// pressed without mouse move event.
UpdateWindowComponentForEvent(target, event);
mouse_down_bounds_ = target->bounds();
mouse_down_offset_in_target_ = event->location();
mouse_down_offset_in_parent_ = mouse_down_offset_in_target_;
@ -192,6 +195,12 @@ bool ToplevelWindowEventFilter::HandleDrag(Window* target, MouseEvent* event) {
return true;
}
void ToplevelWindowEventFilter::UpdateWindowComponentForEvent(
Window* target, MouseEvent* event) {
window_component_ =
target->delegate()->GetNonClientComponent(event->location());
}
gfx::Point ToplevelWindowEventFilter::GetOriginForDrag(
int bounds_change,
Window* target,
@ -240,10 +249,18 @@ gfx::Size ToplevelWindowEventFilter::GetSizeForDrag(int bounds_change,
int x_multiplier = GetXMultiplierForWindowComponent(window_component_);
int y_multiplier = GetYMultiplierForWindowComponent(window_component_);
size.Enlarge(size_change_direction & kBoundsChangeDirection_Horizontal ?
x_multiplier * (first_x - second_x) : 0,
size_change_direction & kBoundsChangeDirection_Vertical ?
y_multiplier * (first_y - second_y) : 0);
int width = size.width() +
(size_change_direction & kBoundsChangeDirection_Horizontal ?
x_multiplier * (first_x - second_x) : 0);
int height = size.height() +
(size_change_direction & kBoundsChangeDirection_Vertical ?
y_multiplier * (first_y - second_y) : 0);
// Enforce minimum window size.
const gfx::Size min_size = target->minimum_size();
size.SetSize(std::max(width, min_size.width()),
std::max(height, min_size.height()));
}
return size;
}

@ -36,6 +36,9 @@ class ToplevelWindowEventFilter : public EventFilter {
// The return value is returned by OnMouseEvent() above.
bool HandleDrag(Window* target, MouseEvent* event);
// Updates the |window_component_| using the |event|'s location.
void UpdateWindowComponentForEvent(Window* window, MouseEvent* event);
// Calculates the new origin of the window during a drag.
gfx::Point GetOriginForDrag(int bounds_change,
Window* target,

@ -9,8 +9,10 @@
#include "ui/aura/event.h"
#include "ui/aura/hit_test.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_desktop_delegate.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/gfx/screen.h"
#if defined(OS_WIN)
// Windows headers define macros for these function names which screw with us.
@ -65,15 +67,9 @@ class ToplevelWindowEventFilterTest : public AuraTestBase {
return w1;
}
void DragFromCenterBy(Window* window, int x, int y) {
gfx::Point click = window->bounds().CenterPoint();
Desktop* desktop= Desktop::GetInstance();
Window::ConvertPointToWindow(window->parent(), desktop->window(), &click);
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_MOVED, click, 0));
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, click, 0));
click.Offset(x, y);
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_DRAGGED, click, 0));
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_RELEASED, click, 0));
void DragFromCenterBy(Window* window, int dx, int dy) {
EventGenerator generator(window);
generator.DragMouseBy(dx, dy);
}
private:
@ -105,11 +101,26 @@ TEST_F(ToplevelWindowEventFilterTest, BottomRight) {
TEST_F(ToplevelWindowEventFilterTest, GrowBox) {
scoped_ptr<Window> w1(CreateWindow(HTGROWBOX));
gfx::Point position = w1->bounds().origin();
DragFromCenterBy(w1.get(), 100, 100);
w1->set_minimum_size(gfx::Size(50, 50));
EventGenerator generator;
generator.MoveMouseToCenterOf(w1.get());
generator.DragMouseBy(100, 100);
// Position should not have changed.
EXPECT_EQ(position, w1->bounds().origin());
// Size should have increased by 100,100.
EXPECT_EQ(gfx::Size(200, 200), w1->bounds().size());
// Shrink the wnidow by (-100, -100).
generator.DragMouseBy(-100, -100);
// Position should not have changed.
EXPECT_EQ(position, w1->bounds().origin());
// Size should have decreased by 100,100.
EXPECT_EQ(gfx::Size(100, 100), w1->bounds().size());
// Enforce minimum size.
generator.DragMouseBy(-60, -60);
EXPECT_EQ(position, w1->bounds().origin());
EXPECT_EQ(gfx::Size(50, 50), w1->bounds().size());
}
TEST_F(ToplevelWindowEventFilterTest, Right) {
@ -185,5 +196,31 @@ TEST_F(ToplevelWindowEventFilterTest, Client) {
EXPECT_EQ(bounds, w1->bounds());
}
TEST_F(ToplevelWindowEventFilterTest, Maximized) {
scoped_ptr<Window> w1(CreateWindow(HTCLIENT));
gfx::Rect workarea = gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get());
// Maximized window cannot be dragged.
gfx::Rect original_bounds = w1->bounds();
w1->Maximize();
EXPECT_EQ(workarea, w1->bounds());
DragFromCenterBy(w1.get(), 100, 100);
EXPECT_EQ(workarea, w1->bounds());
w1->Restore();
EXPECT_EQ(original_bounds, w1->bounds());
}
TEST_F(ToplevelWindowEventFilterTest, Fullscreen) {
scoped_ptr<Window> w1(CreateWindow(HTCLIENT));
gfx::Rect monitor = gfx::Screen::GetMonitorAreaNearestWindow(w1.get());
// Fullscreen window cannot be dragged.
gfx::Rect original_bounds = w1->bounds();
w1->Fullscreen();
EXPECT_EQ(monitor, w1->bounds());
DragFromCenterBy(w1.get(), 100, 100);
EXPECT_EQ(monitor, w1->bounds());
w1->Restore();
EXPECT_EQ(original_bounds, w1->bounds());
}
} // namespace test
} // namespace aura

@ -96,18 +96,18 @@ bool Window::IsVisible() const {
void Window::Maximize() {
if (UpdateShowStateAndRestoreBounds(ui::SHOW_STATE_MAXIMIZED))
SetBounds(gfx::Screen::GetMonitorWorkAreaNearestWindow(this));
SetBoundsInternal(gfx::Screen::GetMonitorWorkAreaNearestWindow(this));
}
void Window::Fullscreen() {
if (UpdateShowStateAndRestoreBounds(ui::SHOW_STATE_FULLSCREEN))
SetBounds(gfx::Screen::GetMonitorAreaNearestWindow(this));
SetBoundsInternal(gfx::Screen::GetMonitorAreaNearestWindow(this));
}
void Window::Restore() {
if (show_state_ != ui::SHOW_STATE_NORMAL) {
show_state_ = ui::SHOW_STATE_NORMAL;
SetBounds(restore_bounds_);
SetBoundsInternal(restore_bounds_);
restore_bounds_.SetRect(0, 0, 0, 0);
}
}
@ -138,21 +138,12 @@ void Window::SetLayoutManager(LayoutManager* layout_manager) {
}
void Window::SetBounds(const gfx::Rect& new_bounds) {
// TODO: funnel this through the Desktop.
gfx::Rect old_bounds = bounds();
bool was_move = old_bounds.size() == new_bounds.size();
layer_->SetBounds(new_bounds);
if (layout_manager_.get())
layout_manager_->OnWindowResized();
if (delegate_)
delegate_->OnBoundsChanged(old_bounds, new_bounds);
if (IsVisible()) {
if (was_move)
layer()->ScheduleDraw();
else
layer()->SchedulePaint(gfx::Rect());
if (show_state_ == ui::SHOW_STATE_MAXIMIZED ||
show_state_ == ui::SHOW_STATE_FULLSCREEN) {
restore_bounds_ = new_bounds;
return;
}
SetBoundsInternal(new_bounds);
}
const gfx::Rect& Window::bounds() const {
@ -401,6 +392,23 @@ internal::RootWindow* Window::GetRoot() {
return parent_ ? parent_->GetRoot() : NULL;
}
void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
const gfx::Rect old_bounds = bounds();
bool was_move = old_bounds.size() == new_bounds.size();
layer_->SetBounds(new_bounds);
if (layout_manager_.get())
layout_manager_->OnWindowResized();
if (delegate_)
delegate_->OnBoundsChanged(old_bounds, new_bounds);
if (IsVisible()) {
if (was_move)
layer()->ScheduleDraw();
else
layer()->SchedulePaint(gfx::Rect());
}
}
void Window::SetVisible(bool visible) {
if (visible == layer_->visible())
return; // No change.

@ -123,6 +123,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
// Changes the bounds of the window.
void SetBounds(const gfx::Rect& new_bounds);
// Sets the minimum size of the window that a user can resize it to.
// A smaller size can still be set using SetBounds().
void set_minimum_size(const gfx::Size& minimum_size) {
minimum_size_ = minimum_size;
}
const gfx::Size& minimum_size() const { return minimum_size_; }
// Marks the a portion of window as needing to be painted.
void SchedulePaintInRect(const gfx::Rect& rect);
@ -244,6 +251,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
virtual internal::RootWindow* GetRoot();
private:
// Changes the bounds of the window without condition.
void SetBoundsInternal(const gfx::Rect& new_bounds);
// Updates the visible state of the layer, but does not make visible-state
// specific changes. Called from Show()/Hide().
void SetVisible(bool visible);
@ -281,6 +291,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
// The original bounds of a maximized/fullscreen window.
gfx::Rect restore_bounds_;
// The minimum size of the window a user can resize to.
gfx::Size minimum_size_;
scoped_ptr<ui::Layer> layer_;
// The Window's parent.

@ -15,6 +15,7 @@
#include "ui/aura/hit_test.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_desktop_delegate.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window_delegate.h"
@ -375,7 +376,7 @@ TEST_F(WindowTest, MoveChildToFront) {
// Various destruction assertions.
TEST_F(WindowTest, CaptureTests) {
Desktop* desktop = Desktop::GetInstance();
aura::Desktop* desktop = aura::Desktop::GetInstance();
CaptureWindowDelegateImpl delegate;
scoped_ptr<Window> window(CreateTestWindowWithDelegate(
&delegate, 0, gfx::Rect(0, 0, 20, 20), NULL));
@ -385,12 +386,11 @@ TEST_F(WindowTest, CaptureTests) {
window->SetCapture();
EXPECT_TRUE(window->HasCapture());
EXPECT_EQ(0, delegate.capture_lost_count());
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(50, 50),
ui::EF_LEFT_BUTTON_DOWN));
EventGenerator generator(gfx::Point(50, 50));
generator.PressLeftButton();
EXPECT_EQ(1, delegate.mouse_event_count());
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50),
ui::EF_LEFT_BUTTON_DOWN));
generator.ReleaseLeftButton();
EXPECT_EQ(2, delegate.mouse_event_count());
delegate.set_mouse_event_count(0);
@ -403,8 +403,7 @@ TEST_F(WindowTest, CaptureTests) {
EXPECT_FALSE(window->HasCapture());
EXPECT_EQ(1, delegate.capture_lost_count());
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(50, 50),
ui::EF_LEFT_BUTTON_DOWN));
generator.PressLeftButton();
EXPECT_EQ(0, delegate.mouse_event_count());
desktop->OnTouchEvent(TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(50, 50),
@ -503,6 +502,13 @@ class ActivateWindowDelegate : public TestWindowDelegate {
should_activate_count_(0) {
}
ActivateWindowDelegate(bool activate)
: activate_(activate),
activated_count_(0),
lost_active_count_(0),
should_activate_count_(0) {
}
void set_activate(bool v) { activate_ = v; }
int activated_count() const { return activated_count_; }
int lost_active_count() const { return lost_active_count_; }
@ -557,8 +563,8 @@ TEST_F(WindowTest, ActivateOnMouse) {
// Click on window2.
gfx::Point press_point = w2->bounds().CenterPoint();
Window::ConvertPointToWindow(w2->parent(), desktop->window(), &press_point);
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, press_point, 0));
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_RELEASED, press_point, 0));
EventGenerator generator(press_point);
generator.ClickLeftButton();
// Window2 should have become active.
EXPECT_EQ(w2.get(), desktop->active_window());
@ -574,8 +580,7 @@ TEST_F(WindowTest, ActivateOnMouse) {
press_point = w1->bounds().CenterPoint();
Window::ConvertPointToWindow(w1->parent(), desktop->window(), &press_point);
d1.set_activate(false);
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, press_point, 0));
desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_RELEASED, press_point, 0));
generator.ClickLeftButton();
// Window2 should still be active and focused.
EXPECT_EQ(w2.get(), desktop->active_window());
@ -820,13 +825,22 @@ TEST_F(WindowTest, Fullscreen) {
EXPECT_EQ(ui::SHOW_STATE_NORMAL, w->show_state());
EXPECT_EQ(original_bounds, w->bounds());
// Fullscreen twice
// Calling Fullscreen() twice should have no additional effect.
w->Fullscreen();
w->Fullscreen();
EXPECT_EQ(desktop_bounds, w->bounds());
w->Restore();
EXPECT_EQ(ui::SHOW_STATE_NORMAL, w->show_state());
EXPECT_EQ(original_bounds, w->bounds());
// Calling SetBounds() in fullscreen mode should only update the
// restore bounds not change the bounds of the window.
gfx::Rect new_bounds(50, 50, 50, 50);
w->Fullscreen();
w->SetBounds(new_bounds);
EXPECT_EQ(desktop_bounds, w->bounds());
w->Restore();
EXPECT_EQ(new_bounds, w->bounds());
}
TEST_F(WindowTest, Maximized) {
@ -868,6 +882,15 @@ TEST_F(WindowTest, Maximized) {
w->Restore();
EXPECT_EQ(ui::SHOW_STATE_NORMAL, w->show_state());
EXPECT_EQ(original_bounds, w->bounds());
// Calling SetBounds() in maximized mode mode should only update the
// restore bounds not change the bounds of the window.
gfx::Rect new_bounds(50, 50, 50, 50);
w->Maximize();
w->SetBounds(new_bounds);
EXPECT_EQ(max_bounds, w->bounds());
w->Restore();
EXPECT_EQ(new_bounds, w->bounds());
}
// Various assertions for activating/deactivating.
@ -917,6 +940,48 @@ TEST_F(WindowTest, IsOrContainsFullscreenWindow) {
EXPECT_FALSE(root->IsOrContainsFullscreenWindow());
}
class ToplevelWindowTest : public WindowTest {
public:
ToplevelWindowTest() {}
virtual ~ToplevelWindowTest() {}
virtual void SetUp() OVERRIDE {
WindowTest::SetUp();
toplevel_container_.Init();
toplevel_container_.SetParent(aura::Desktop::GetInstance()->window());
toplevel_container_.SetBounds(
aura::Desktop::GetInstance()->window()->bounds());
toplevel_container_.Show();
}
virtual void TearDown() OVERRIDE {
toplevel_container_.Hide();
toplevel_container_.SetParent(NULL);
WindowTest::TearDown();
}
Window* CreateTestToplevelWindow(
WindowDelegate* delegate, const gfx::Rect& bounds) {
return CreateTestWindowWithDelegate(
delegate, 0 /* id */, bounds, &toplevel_container_);
}
ToplevelWindowContainer toplevel_container_;
private:
DISALLOW_COPY_AND_ASSIGN(ToplevelWindowTest);
};
TEST_F(ToplevelWindowTest, TopMostActivate) {
ActivateWindowDelegate activate;
ActivateWindowDelegate non_activate(false);
scoped_ptr<Window> w1(CreateTestToplevelWindow(&non_activate, gfx::Rect()));
scoped_ptr<Window> w2(CreateTestToplevelWindow(&activate, gfx::Rect()));
scoped_ptr<Window> w3(CreateTestToplevelWindow(&non_activate, gfx::Rect()));
EXPECT_EQ(w2.get(), toplevel_container_.GetTopmostWindowToActivate(NULL));
}
class WindowObserverTest : public WindowTest,
public WindowObserver {
public:

@ -66,6 +66,10 @@ class UI_EXPORT Point {
return copy;
}
Point Middle(const Point& other) const {
return Point((x_ + other.x_) / 2, (y_ + other.y_) / 2);
}
bool operator==(const Point& rhs) const {
return x_ == rhs.x_ && y_ == rhs.y_;
}

@ -102,6 +102,7 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
// TODO(beng): respect |params| authoritah wrt transparency.
window_->layer()->SetFillsBoundsOpaquely(false);
delegate_->OnNativeWidgetCreated();
window_->set_minimum_size(delegate_->GetMinimumSize());
window_->SetBounds(params.bounds);
window_->SetParent(
params.type == Widget::InitParams::TYPE_MENU ? NULL : params.parent);

@ -904,7 +904,7 @@ void Widget::OnNativeWidgetDestroyed() {
}
gfx::Size Widget::GetMinimumSize() {
return non_client_view_ ? non_client_view_->GetMinimumSize() : gfx::Size();
return non_client_view_ ? non_client_view_->GetMinimumSize() : minimum_size_;
}
void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) {
@ -1160,12 +1160,13 @@ bool Widget::GetSavedWindowPlacement(gfx::Rect* bounds,
if (!widget_delegate_->ShouldRestoreWindowSize()) {
bounds->set_size(non_client_view_->GetPreferredSize());
} else {
gfx::Size minimum_size = GetMinimumSize();
// Make sure the bounds are at least the minimum size.
if (bounds->width() < minimum_size_.width())
bounds->set_width(minimum_size_.width());
if (bounds->width() < minimum_size.width())
bounds->set_width(minimum_size.width());
if (bounds->height() < minimum_size_.height())
bounds->set_height(minimum_size_.height());
if (bounds->height() < minimum_size.height())
bounds->set_height(minimum_size.height());
}
return true;
}

@ -709,7 +709,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// |saved_show_state_| is maximized.
gfx::Rect initial_restored_bounds_;
// The smallest size the window can be.
// The smallest size the user can resize the window.
gfx::Size minimum_size_;
// Focus is automatically set to the view provided by the delegate