summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 07:07:55 +0000
committerkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 07:07:55 +0000
commit3075983f95a3554e915bc89994a6b0f492ea3bd4 (patch)
tree9545cc03a19568cd213050c28c8323177165ebbb /ash
parent941dcc7e34455b128cf7de0c36ceea6e365b2a26 (diff)
downloadchromium_src-3075983f95a3554e915bc89994a6b0f492ea3bd4.zip
chromium_src-3075983f95a3554e915bc89994a6b0f492ea3bd4.tar.gz
chromium_src-3075983f95a3554e915bc89994a6b0f492ea3bd4.tar.bz2
Make resizing of attached windows in ash honour min/max size constraints.
BUG=152065 Review URL: https://chromiumcodereview.appspot.com/11416194 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169874 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/wm/workspace/workspace_window_resizer.cc234
-rw-r--r--ash/wm/workspace/workspace_window_resizer.h58
-rw-r--r--ash/wm/workspace/workspace_window_resizer_unittest.cc237
3 files changed, 447 insertions, 82 deletions
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index a717314..cd8996a 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -235,6 +235,75 @@ const int WorkspaceWindowResizer::kMinOnscreenHeight = 32;
// static
const int WorkspaceWindowResizer::kScreenEdgeInset = 8;
+// Represents the width or height of a window with constraints on its minimum
+// and maximum size. 0 represents a lack of a constraint.
+class WindowSize {
+ public:
+ WindowSize(int size, int min, int max)
+ : size_(size),
+ min_(min),
+ max_(max) {
+ // Grow the min/max bounds to include the starting size.
+ if (is_underflowing())
+ min_ = size_;
+ if (is_overflowing())
+ max_ = size_;
+ }
+
+ bool is_at_capacity(bool shrinking) {
+ return size_ == (shrinking ? min_ : max_);
+ }
+
+ int size() const {
+ return size_;
+ }
+
+ bool has_min() const {
+ return min_ != 0;
+ }
+
+ bool has_max() const {
+ return max_ != 0;
+ }
+
+ bool is_valid() const {
+ return !is_overflowing() && !is_underflowing();
+ }
+
+ bool is_overflowing() const {
+ return has_max() && size_ > max_;
+ }
+
+ bool is_underflowing() const {
+ return has_min() && size_ < min_;
+ }
+
+ // Add |amount| to this WindowSize not exceeding min or max size constraints.
+ // Returns by how much |size_| + |amount| exceeds the min/max constraints.
+ int Add(int amount) {
+ DCHECK(is_valid());
+ int new_value = size_ + amount;
+
+ if (has_min() && new_value < min_) {
+ size_ = min_;
+ return new_value - min_;
+ }
+
+ if (has_max() && new_value > max_) {
+ size_ = max_;
+ return new_value - max_;
+ }
+
+ size_ = new_value;
+ return 0;
+ }
+
+ private:
+ int size_;
+ int min_;
+ int max_;
+};
+
WorkspaceWindowResizer::~WorkspaceWindowResizer() {
Shell* shell = Shell::GetInstance();
shell->mouse_cursor_filter()->set_mouse_warp_mode(
@@ -299,7 +368,7 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent,
}
if (!attached_windows_.empty())
- LayoutAttachedWindows(bounds);
+ LayoutAttachedWindows(&bounds);
if (bounds != window()->bounds()) {
bool destroyed = false;
destroyed_ = &destroyed;
@@ -446,24 +515,10 @@ WorkspaceWindowResizer::WorkspaceWindowResizer(
// This way we don't snap on resize.
int min_size = std::min(initial_size,
std::max(PrimaryAxisSize(min), kMinOnscreenSize));
- min_size_.push_back(min_size);
total_min_ += min_size;
total_initial_size_ += initial_size;
total_available += std::max(min_size, initial_size) - min_size;
}
-
- for (size_t i = 0; i < attached_windows_.size(); ++i) {
- expand_fraction_.push_back(
- static_cast<float>(initial_size_[i]) /
- static_cast<float>(total_initial_size_));
- if (total_initial_size_ != total_min_) {
- compress_fraction_.push_back(
- static_cast<float>(initial_size_[i] - min_size_[i]) /
- static_cast<float>(total_available));
- } else {
- compress_fraction_.push_back(0.0f);
- }
- }
}
gfx::Rect WorkspaceWindowResizer::GetFinalBounds(
@@ -476,17 +531,30 @@ gfx::Rect WorkspaceWindowResizer::GetFinalBounds(
}
void WorkspaceWindowResizer::LayoutAttachedWindows(
- const gfx::Rect& bounds) {
+ gfx::Rect* bounds) {
gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(window()));
+ int initial_size = PrimaryAxisSize(details_.initial_bounds_in_parent.size());
+ int current_size = PrimaryAxisSize(bounds->size());
+ int start = PrimaryAxisCoordinate(bounds->right(), bounds->bottom());
+ int end = PrimaryAxisCoordinate(work_area.right(), work_area.bottom());
+
+ int delta = current_size - initial_size;
+ int available_size = end - start;
std::vector<int> sizes;
- CalculateAttachedSizes(
- PrimaryAxisSize(details_.initial_bounds_in_parent.size()),
- PrimaryAxisSize(bounds.size()),
- PrimaryAxisCoordinate(bounds.right(), bounds.bottom()),
- PrimaryAxisCoordinate(work_area.right(), work_area.bottom()),
- &sizes);
+ int leftovers = CalculateAttachedSizes(delta, available_size, &sizes);
+
+ // Reallocate any leftover pixels back into the main window. This is
+ // necessary when, for example, the main window shrinks, but none of the
+ // attached windows can grow without exceeding their max size constraints.
+ // Adding the pixels back to the main window effectively prevents the main
+ // window from resizing too far.
+ if (details_.window_component == HTRIGHT)
+ bounds->set_width(bounds->width() + leftovers);
+ else
+ bounds->set_height(bounds->height() + leftovers);
+
DCHECK_EQ(attached_windows_.size(), sizes.size());
- int last = PrimaryAxisCoordinate(bounds.right(), bounds.bottom());
+ int last = PrimaryAxisCoordinate(bounds->right(), bounds->bottom());
for (size_t i = 0; i < attached_windows_.size(); ++i) {
gfx::Rect attached_bounds(attached_windows_[i]->bounds());
if (details_.window_component == HTRIGHT) {
@@ -501,40 +569,98 @@ void WorkspaceWindowResizer::LayoutAttachedWindows(
}
}
-void WorkspaceWindowResizer::CalculateAttachedSizes(
- int initial_size,
- int current_size,
- int start,
- int end,
+int WorkspaceWindowResizer::CalculateAttachedSizes(
+ int delta,
+ int available_size,
std::vector<int>* sizes) const {
- sizes->clear();
- if (current_size < initial_size) {
- // If the primary window is sized smaller, resize the attached windows.
- int current = start;
- int delta = initial_size - current_size;
- for (size_t i = 0; i < attached_windows_.size(); ++i) {
- int next = current + initial_size_[i] + expand_fraction_[i] * delta;
- if (i + 1 == attached_windows_.size())
- next = start + total_initial_size_ + (initial_size - current_size);
- sizes->push_back(next - current);
- current = next;
- }
- } else if (start <= end - total_initial_size_) {
- // All the windows fit at their initial size; tile them horizontally.
- for (size_t i = 0; i < attached_windows_.size(); ++i)
- sizes->push_back(initial_size_[i]);
+ std::vector<WindowSize> window_sizes;
+ CreateBucketsForAttached(&window_sizes);
+
+ // How much we need to grow the attached by (collectively).
+ int grow_attached_by = 0;
+ if (delta > 0) {
+ // If the attached windows don't fit when at their initial size, we will
+ // have to shrink them by how much they overflow.
+ if (total_initial_size_ >= available_size)
+ grow_attached_by = available_size - total_initial_size_;
} else {
- DCHECK_NE(total_initial_size_, total_min_);
- int delta = total_initial_size_ - (end - start);
- int current = start;
- for (size_t i = 0; i < attached_windows_.size(); ++i) {
- int size = initial_size_[i] -
- static_cast<int>(compress_fraction_[i] * delta);
- if (i + 1 == attached_windows_.size())
- size = end - current;
- current += size;
- sizes->push_back(size);
+ // If we're shrinking, we grow the attached so the total size remains
+ // constant.
+ grow_attached_by = -delta;
+ }
+
+ int leftover_pixels = 0;
+ while (grow_attached_by != 0) {
+ int leftovers = GrowFairly(grow_attached_by, window_sizes);
+ if (leftovers == grow_attached_by) {
+ leftover_pixels = leftovers;
+ break;
}
+ grow_attached_by = leftovers;
+ }
+
+ for (size_t i = 0; i < window_sizes.size(); ++i)
+ sizes->push_back(window_sizes[i].size());
+
+ return leftover_pixels;
+}
+
+int WorkspaceWindowResizer::GrowFairly(
+ int pixels,
+ std::vector<WindowSize>& sizes) const {
+ bool shrinking = pixels < 0;
+ std::vector<WindowSize*> nonfull_windows;
+ for (size_t i = 0; i < sizes.size(); ++i) {
+ if (!sizes[i].is_at_capacity(shrinking))
+ nonfull_windows.push_back(&sizes[i]);
+ }
+ std::vector<float> ratios;
+ CalculateGrowthRatios(nonfull_windows, &ratios);
+
+ int remaining_pixels = pixels;
+ bool add_leftover_pixels_to_last = true;
+ for (size_t i = 0; i < nonfull_windows.size(); ++i) {
+ int grow_by = pixels * ratios[i];
+ // Put any leftover pixels into the last window.
+ if (i == nonfull_windows.size() - 1 && add_leftover_pixels_to_last)
+ grow_by = remaining_pixels;
+ int remainder = nonfull_windows[i]->Add(grow_by);
+ int consumed = grow_by - remainder;
+ remaining_pixels -= consumed;
+ if (nonfull_windows[i]->is_at_capacity(shrinking) && remainder > 0) {
+ // Because this window overflowed, some of the pixels in
+ // |remaining_pixels| aren't there due to rounding errors. Rather than
+ // unfairly giving all those pixels to the last window, we refrain from
+ // allocating them so that this function can be called again to distribute
+ // the pixels fairly.
+ add_leftover_pixels_to_last = false;
+ }
+ }
+ return remaining_pixels;
+}
+
+void WorkspaceWindowResizer::CalculateGrowthRatios(
+ const std::vector<WindowSize*>& sizes,
+ std::vector<float>* out_ratios) const {
+ DCHECK(out_ratios->empty());
+ int total_value = 0;
+ for (size_t i = 0; i < sizes.size(); ++i)
+ total_value += sizes[i]->size();
+
+ for (size_t i = 0; i < sizes.size(); ++i)
+ out_ratios->push_back(
+ (static_cast<float>(sizes[i]->size())) / total_value);
+}
+
+void WorkspaceWindowResizer::CreateBucketsForAttached(
+ std::vector<WindowSize>* sizes) const {
+ for (size_t i = 0; i < attached_windows_.size(); i++) {
+ int initial_size = initial_size_[i];
+ aura::WindowDelegate* delegate = attached_windows_[i]->delegate();
+ int min = PrimaryAxisSize(delegate->GetMinimumSize());
+ int max = PrimaryAxisSize(delegate->GetMaximumSize());
+
+ sizes->push_back(WindowSize(initial_size, min, max));
}
}
diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h
index c952f11..a948cc8 100644
--- a/ash/wm/workspace/workspace_window_resizer.h
+++ b/ash/wm/workspace/workspace_window_resizer.h
@@ -27,6 +27,7 @@ namespace internal {
class PhantomWindowController;
class SnapSizer;
+class WindowSize;
// WindowResizer implementation for workspaces. This enforces that windows are
// not allowed to vertically move or resize outside of the work area. As windows
@@ -94,17 +95,36 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
gfx::Rect GetFinalBounds(const gfx::Rect& bounds) const;
// Lays out the attached windows. |bounds| is the bounds of the main window.
- void LayoutAttachedWindows(const gfx::Rect& bounds);
-
- // Calculates the size (along the primary axis) of the attached windows.
- // |initial_size| is the initial size of the main window, |current_size| the
- // new size of the main window, |start| the position to layout the attached
- // windows from and |end| the coordinate to position to.
- void CalculateAttachedSizes(int initial_size,
- int current_size,
- int start,
- int end,
- std::vector<int>* sizes) const;
+ void LayoutAttachedWindows(gfx::Rect* bounds);
+
+ // Calculates the new sizes of the attached windows, given that the main
+ // window has been resized (along the primary axis) by |delta|.
+ // |available_size| is the maximum length of the space that the attached
+ // windows are allowed to occupy (ie: the distance between the right/bottom
+ // edge of the primary window and the right/bottom of the desktop area).
+ // Populates |sizes| with the desired sizes of the attached windows, and
+ // returns the number of pixels that couldn't be allocated to the attached
+ // windows (due to min/max size constraints).
+ // Note the return value can be positive or negative, a negative value
+ // indicating that that many pixels couldn't be removed from the attached
+ // windows.
+ int CalculateAttachedSizes(
+ int delta,
+ int available_size,
+ std::vector<int>* sizes) const;
+
+ // Divides |amount| evenly between |sizes|. If |amount| is negative it
+ // indicates how many pixels |sizes| should be shrunk by.
+ // Returns how many pixels failed to be allocated/removed from |sizes|.
+ int GrowFairly(int amount, std::vector<WindowSize>& sizes) const;
+
+ // Calculate the ratio of pixels that each WindowSize in |sizes| should
+ // receive when growing or shrinking.
+ void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes,
+ std::vector<float>* out_ratios) const;
+
+ // Adds a WindowSize to |sizes| for each attached window.
+ void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const;
// If possible snaps the window to a neary window. Updates |bounds| if there
// was a close enough window.
@@ -177,21 +197,7 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
// primary axis.
std::vector<int> initial_size_;
- // The min size of each of the windows in |attached_windows_| along the
- // primary axis.
- std::vector<int> min_size_;
-
- // The amount each of the windows in |attached_windows_| can be compressed.
- // This is a fraction of the amount a window can be compressed over the total
- // space the windows can be compressed.
- std::vector<float> compress_fraction_;
-
- // The amount each of the windows in |attached_windows_| should be expanded
- // by. This is used when the user drags to the left/up. In this case the main
- // window shrinks and the attached windows expand.
- std::vector<float> expand_fraction_;
-
- // Sum of sizes in |min_size_|.
+ // Sum of the minimum sizes of the attached windows.
int total_min_;
// Sum of the sizes in |initial_size_|.
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index d8570ee..23ba208 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -97,12 +97,19 @@ class WorkspaceWindowResizerTest : public test::AshTestBase {
window3_->Init(ui::LAYER_NOT_DRAWN);
window3_->SetParent(NULL);
window3_->set_id(3);
+
+ window4_.reset(new aura::Window(&delegate4_));
+ window4_->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ window4_->Init(ui::LAYER_NOT_DRAWN);
+ window4_->SetParent(NULL);
+ window4_->set_id(4);
}
virtual void TearDown() OVERRIDE {
window_.reset();
window2_.reset();
window3_.reset();
+ window4_.reset();
AshTestBase::TearDown();
}
@@ -144,9 +151,11 @@ class WorkspaceWindowResizerTest : public test::AshTestBase {
TestWindowDelegate delegate_;
TestWindowDelegate delegate2_;
TestWindowDelegate delegate3_;
+ TestWindowDelegate delegate4_;
scoped_ptr<aura::Window> window_;
scoped_ptr<aura::Window> window2_;
scoped_ptr<aura::Window> window3_;
+ scoped_ptr<aura::Window> window4_;
private:
DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest);
@@ -416,8 +425,8 @@ TEST_F(WorkspaceWindowResizerTest, MAYBE_AttachedResize_BOTTOM_3) {
// Move it 296 things should compress.
resizer->Drag(CalculateDragPoint(*resizer, -10, 296), 0);
EXPECT_EQ("300,100 300x496", window_->bounds().ToString());
- EXPECT_EQ("300,596 200x122", window2_->bounds().ToString());
- EXPECT_EQ("300,718 200x82", window3_->bounds().ToString());
+ EXPECT_EQ("300,596 200x123", window2_->bounds().ToString());
+ EXPECT_EQ("300,719 200x81", window3_->bounds().ToString());
// Move it so much everything ends up at its min.
resizer->Drag(CalculateDragPoint(*resizer, 50, 798), 0);
@@ -1523,5 +1532,229 @@ TEST_F(WorkspaceWindowResizerTest, PhantomSnapMaxSize) {
}
}
+TEST_F(WorkspaceWindowResizerTest, DontRewardRightmostWindowForOverflows) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Four 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
+ delegate2_.set_max_size(gfx::Size(101, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 51 to the left, which should contract w1 and expand w2-4.
+ // w2 will hit its max size straight away, and in doing so will leave extra
+ // pixels that a naive implementation may award to the rightmost window. A
+ // fair implementation will give 25 pixels to each of the other windows.
+ resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
+ EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
+ EXPECT_EQ("149,100 101x100", window2_->bounds().ToString());
+ EXPECT_EQ("250,100 125x100", window3_->bounds().ToString());
+ EXPECT_EQ("375,100 125x100", window4_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, DontExceedMaxWidth) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Four 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
+ delegate2_.set_max_size(gfx::Size(101, 0));
+ delegate3_.set_max_size(gfx::Size(101, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 52 to the left, which should contract w1 and expand w2-4.
+ resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
+ EXPECT_EQ("100,100 48x100", window_->bounds().ToString());
+ EXPECT_EQ("148,100 101x100", window2_->bounds().ToString());
+ EXPECT_EQ("249,100 101x100", window3_->bounds().ToString());
+ EXPECT_EQ("350,100 150x100", window4_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, DontExceedMaxHeight) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Four 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
+ window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
+ window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
+ delegate2_.set_max_size(gfx::Size(0, 101));
+ delegate3_.set_max_size(gfx::Size(0, 101));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTBOTTOM, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 52 up, which should contract w1 and expand w2-4.
+ resizer->Drag(CalculateDragPoint(*resizer, 0, -52), 0);
+ EXPECT_EQ("100,100 100x48", window_->bounds().ToString());
+ EXPECT_EQ("100,148 100x101", window2_->bounds().ToString());
+ EXPECT_EQ("100,249 100x101", window3_->bounds().ToString());
+ EXPECT_EQ("100,350 100x150", window4_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, DontExceedMinHeight) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 500));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Four 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
+ window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
+ window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
+ delegate2_.set_min_size(gfx::Size(0, 99));
+ delegate3_.set_min_size(gfx::Size(0, 99));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTBOTTOM, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 52 down, which should expand w1 and contract w2-4.
+ resizer->Drag(CalculateDragPoint(*resizer, 0, 52), 0);
+ EXPECT_EQ("100,100 100x152", window_->bounds().ToString());
+ EXPECT_EQ("100,252 100x99", window2_->bounds().ToString());
+ EXPECT_EQ("100,351 100x99", window3_->bounds().ToString());
+ EXPECT_EQ("100,450 100x50", window4_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, DontExpandRightmostPastMaxWidth) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Three 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ delegate3_.set_max_size(gfx::Size(101, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 51 to the left, which should contract w1 and expand w2-3.
+ resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
+ EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
+ EXPECT_EQ("149,100 150x100", window2_->bounds().ToString());
+ EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, DontContractMainIfAttachedAreStretched) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(600, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Three 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ delegate2_.set_max_size(gfx::Size(101, 0));
+ delegate3_.set_max_size(gfx::Size(101, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 52 to the left, which should contract w1 and expand w2-3.
+ resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
+ EXPECT_EQ("100,100 98x100", window_->bounds().ToString());
+ EXPECT_EQ("198,100 101x100", window2_->bounds().ToString());
+ EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, MainWindowHonoursMaxWidth) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(400, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Three 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ delegate_.set_max_size(gfx::Size(102, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 50 to the right, which should expand w1 and contract w2-3, as they
+ // won't fit in the root window in their original sizes.
+ resizer->Drag(CalculateDragPoint(*resizer, 50, 0), 0);
+ EXPECT_EQ("100,100 102x100", window_->bounds().ToString());
+ EXPECT_EQ("202,100 99x100", window2_->bounds().ToString());
+ EXPECT_EQ("301,100 99x100", window3_->bounds().ToString());
+}
+
+TEST_F(WorkspaceWindowResizerTest, MainWindowHonoursMinWidth) {
+ aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+ root->SetHostSize(gfx::Size(400, 800));
+
+ Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
+
+ // Three 100x100 windows flush against eachother, starting at 100,100.
+ window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
+ window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
+ window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
+ delegate_.set_min_size(gfx::Size(98, 0));
+
+ std::vector<aura::Window*> windows;
+ windows.push_back(window2_.get());
+ windows.push_back(window3_.get());
+ windows.push_back(window4_.get());
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTRIGHT, windows));
+ ASSERT_TRUE(resizer.get());
+ // Move it 50 to the left, which should contract w1 and expand w2-3.
+ resizer->Drag(CalculateDragPoint(*resizer, -50, 0), 0);
+ EXPECT_EQ("100,100 98x100", window_->bounds().ToString());
+ EXPECT_EQ("198,100 101x100", window2_->bounds().ToString());
+ EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
+}
+
} // namespace internal
} // namespace ash