diff options
Diffstat (limited to 'chromium/ash/wm/workspace/workspace_window_resizer_unittest.cc')
-rw-r--r-- | chromium/ash/wm/workspace/workspace_window_resizer_unittest.cc | 1978 |
1 files changed, 1978 insertions, 0 deletions
diff --git a/chromium/ash/wm/workspace/workspace_window_resizer_unittest.cc b/chromium/ash/wm/workspace/workspace_window_resizer_unittest.cc new file mode 100644 index 00000000000..8459c54ef5f --- /dev/null +++ b/chromium/ash/wm/workspace/workspace_window_resizer_unittest.cc @@ -0,0 +1,1978 @@ +// Copyright (c) 2012 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 "ash/wm/workspace/workspace_window_resizer.h" + +#include "ash/ash_constants.h" +#include "ash/ash_switches.h" +#include "ash/display/display_controller.h" +#include "ash/root_window_controller.h" +#include "ash/screen_ash.h" +#include "ash/shelf/shelf_layout_manager.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_util.h" +#include "ash/wm/workspace/phantom_window_controller.h" +#include "ash/wm/workspace/snap_sizer.h" +#include "ash/wm/workspace_controller.h" +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/screen.h" +#include "ui/views/widget/widget.h" + +namespace ui { + +// Class to provide access to SlideAnimation internals for testing. +class SlideAnimation::TestApi { + public: + explicit TestApi(SlideAnimation* animation) : animation_(animation) {} + + void SetStartTime(base::TimeTicks ticks) { + animation_->SetStartTime(ticks); + } + + void Step(base::TimeTicks ticks) { + animation_->Step(ticks); + } + + void RunTillComplete() { + SetStartTime(base::TimeTicks()); + Step(base::TimeTicks() + + base::TimeDelta::FromMilliseconds(animation_->GetSlideDuration())); + EXPECT_EQ(1.0, animation_->GetCurrentValue()); + } + + private: + SlideAnimation* animation_; + + DISALLOW_COPY_AND_ASSIGN(TestApi); +}; + +} + +namespace ash { +namespace internal { +namespace { + +const int kRootHeight = 600; + +// A simple window delegate that returns the specified min size. +class TestWindowDelegate : public aura::test::TestWindowDelegate { + public: + TestWindowDelegate() { + } + virtual ~TestWindowDelegate() {} + + void set_min_size(const gfx::Size& size) { + min_size_ = size; + } + + void set_max_size(const gfx::Size& size) { + max_size_ = size; + } + + private: + // Overridden from aura::Test::TestWindowDelegate: + virtual gfx::Size GetMinimumSize() const OVERRIDE { + return min_size_; + } + + virtual gfx::Size GetMaximumSize() const OVERRIDE { + return max_size_; + } + + gfx::Size min_size_; + gfx::Size max_size_; + + DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate); +}; + +class WorkspaceWindowResizerTest : public test::AshTestBase { + public: + WorkspaceWindowResizerTest() {} + virtual ~WorkspaceWindowResizerTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + UpdateDisplay(base::StringPrintf("800x%d", kRootHeight)); + + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + gfx::Rect root_bounds(root->bounds()); +#if defined(OS_WIN) + // RootWindow and Display can't resize on Windows Ash. + // http://crbug.com/165962 + EXPECT_EQ(kRootHeight, root_bounds.height()); +#endif + EXPECT_EQ(800, root_bounds.width()); + Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets()); + window_.reset(new aura::Window(&delegate_)); + window_->SetType(aura::client::WINDOW_TYPE_NORMAL); + window_->Init(ui::LAYER_NOT_DRAWN); + SetDefaultParentByPrimaryRootWindow(window_.get()); + window_->set_id(1); + + window2_.reset(new aura::Window(&delegate2_)); + window2_->SetType(aura::client::WINDOW_TYPE_NORMAL); + window2_->Init(ui::LAYER_NOT_DRAWN); + SetDefaultParentByPrimaryRootWindow(window2_.get()); + window2_->set_id(2); + + window3_.reset(new aura::Window(&delegate3_)); + window3_->SetType(aura::client::WINDOW_TYPE_NORMAL); + window3_->Init(ui::LAYER_NOT_DRAWN); + SetDefaultParentByPrimaryRootWindow(window3_.get()); + window3_->set_id(3); + + window4_.reset(new aura::Window(&delegate4_)); + window4_->SetType(aura::client::WINDOW_TYPE_NORMAL); + window4_->Init(ui::LAYER_NOT_DRAWN); + SetDefaultParentByPrimaryRootWindow(window4_.get()); + window4_->set_id(4); + } + + virtual void TearDown() OVERRIDE { + window_.reset(); + window2_.reset(); + window3_.reset(); + window4_.reset(); + touch_resize_window_.reset(); + AshTestBase::TearDown(); + } + + // Returns a string identifying the z-order of each of the known child windows + // of |parent|. The returned string constains the id of the known windows and + // is ordered from topmost to bottomost windows. + std::string WindowOrderAsString(aura::Window* parent) const { + std::string result; + const aura::Window::Windows& windows = parent->children(); + for (aura::Window::Windows::const_reverse_iterator i = windows.rbegin(); + i != windows.rend(); ++i) { + if (*i == window_ || *i == window2_ || *i == window3_) { + if (!result.empty()) + result += " "; + result += base::IntToString((*i)->id()); + } + } + return result; + } + + protected: + gfx::Point CalculateDragPoint(const WorkspaceWindowResizer& resizer, + int delta_x, + int delta_y) const { + gfx::Point location = resizer.GetInitialLocation(); + location.set_x(location.x() + delta_x); + location.set_y(location.y() + delta_y); + return location; + } + + std::vector<aura::Window*> empty_windows() const { + return std::vector<aura::Window*>(); + } + + internal::ShelfLayoutManager* shelf_layout_manager() { + return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); + } + + void InitTouchResizeWindow(const gfx::Rect& bounds, int window_component) { + touch_resize_delegate_.set_window_component(window_component); + touch_resize_window_.reset( + CreateTestWindowInShellWithDelegate(&touch_resize_delegate_, 0, + bounds)); + gfx::Insets mouse_insets = gfx::Insets(-ash::kResizeOutsideBoundsSize, + -ash::kResizeOutsideBoundsSize, + -ash::kResizeOutsideBoundsSize, + -ash::kResizeOutsideBoundsSize); + gfx::Insets touch_insets = mouse_insets.Scale( + ash::kResizeOutsideBoundsScaleForTouch); + touch_resize_window_->SetHitTestBoundsOverrideOuter(mouse_insets, + touch_insets); + touch_resize_window_->set_hit_test_bounds_override_inner(mouse_insets); + } + + // Simulate running the animation. + void RunAnimationTillComplete(ui::SlideAnimation* animation) { + ui::SlideAnimation::TestApi test_api(animation); + test_api.RunTillComplete(); + } + + 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_; + + TestWindowDelegate touch_resize_delegate_; + scoped_ptr<aura::Window> touch_resize_window_; + + private: + DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest); +}; + +class WorkspaceWindowResizerTestSticky : public WorkspaceWindowResizerTest { + public: + WorkspaceWindowResizerTestSticky() {} + virtual ~WorkspaceWindowResizerTestSticky() {} + + virtual void SetUp() OVERRIDE { + CommandLine::ForCurrentProcess()->AppendSwitch( + ash::switches::kAshEnableStickyEdges); + WorkspaceWindowResizerTest::SetUp(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTestSticky); +}; + +} // namespace + +// Assertions around attached window resize dragging from the right with 2 +// windows. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_2) { + window_->SetBounds(gfx::Rect(0, 300, 400, 300)); + window2_->SetBounds(gfx::Rect(400, 200, 100, 200)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the right, which should expand w1 and push w2. + resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0); + EXPECT_EQ("0,300 500x300", window_->bounds().ToString()); + EXPECT_EQ("500,200 100x200", window2_->bounds().ToString()); + + // Push off the screen, w2 should be resized to its min. + delegate2_.set_min_size(gfx::Size(20, 20)); + resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0); + EXPECT_EQ("0,300 780x300", window_->bounds().ToString()); + EXPECT_EQ("780,200 20x200", window2_->bounds().ToString()); + + // Move back to 100 and verify w2 gets its original size. + resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0); + EXPECT_EQ("0,300 500x300", window_->bounds().ToString()); + EXPECT_EQ("500,200 100x200", window2_->bounds().ToString()); + + // Revert and make sure everything moves back. + resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0); + resizer->RevertDrag(); + EXPECT_EQ("0,300 400x300", window_->bounds().ToString()); + EXPECT_EQ("400,200 100x200", window2_->bounds().ToString()); +} + +// Assertions around collapsing and expanding. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_Compress) { + window_->SetBounds(gfx::Rect( 0, 300, 400, 300)); + window2_->SetBounds(gfx::Rect(400, 200, 100, 200)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the left, which should expand w2 and collapse w1. + resizer->Drag(CalculateDragPoint(*resizer, -100, 10), 0); + EXPECT_EQ("0,300 300x300", window_->bounds().ToString()); + EXPECT_EQ("300,200 200x200", window2_->bounds().ToString()); + + // Collapse all the way to w1's min. + delegate_.set_min_size(gfx::Size(20, 20)); + resizer->Drag(CalculateDragPoint(*resizer, -800, 20), 0); + EXPECT_EQ("0,300 20x300", window_->bounds().ToString()); + EXPECT_EQ("20,200 480x200", window2_->bounds().ToString()); + + // Move 100 to the left. + resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0); + EXPECT_EQ("0,300 500x300", window_->bounds().ToString()); + EXPECT_EQ("500,200 100x200", window2_->bounds().ToString()); + + // Back to -100. + resizer->Drag(CalculateDragPoint(*resizer, -100, 20), 0); + EXPECT_EQ("0,300 300x300", window_->bounds().ToString()); + EXPECT_EQ("300,200 200x200", window2_->bounds().ToString()); +} + +// Assertions around attached window resize dragging from the right with 3 +// windows. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3) { + window_->SetBounds(gfx::Rect( 100, 300, 200, 300)); + window2_->SetBounds(gfx::Rect(300, 300, 150, 200)); + window3_->SetBounds(gfx::Rect(450, 300, 100, 200)); + delegate2_.set_min_size(gfx::Size(52, 50)); + delegate3_.set_min_size(gfx::Size(38, 50)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + windows.push_back(window3_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the right, which should expand w1 and push w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0); + EXPECT_EQ("100,300 300x300", window_->bounds().ToString()); + EXPECT_EQ("400,300 150x200", window2_->bounds().ToString()); + EXPECT_EQ("550,300 100x200", window3_->bounds().ToString()); + + // Move it 300, things should compress. + resizer->Drag(CalculateDragPoint(*resizer, 300, -10), 0); + EXPECT_EQ("100,300 500x300", window_->bounds().ToString()); + EXPECT_EQ("600,300 120x200", window2_->bounds().ToString()); + EXPECT_EQ("720,300 80x200", window3_->bounds().ToString()); + + // Move it so much the last two end up at their min. + resizer->Drag(CalculateDragPoint(*resizer, 800, 50), 0); + EXPECT_EQ("100,300 610x300", window_->bounds().ToString()); + EXPECT_EQ("710,300 52x200", window2_->bounds().ToString()); + EXPECT_EQ("762,300 38x200", window3_->bounds().ToString()); + + // Revert and make sure everything moves back. + resizer->RevertDrag(); + EXPECT_EQ("100,300 200x300", window_->bounds().ToString()); + EXPECT_EQ("300,300 150x200", window2_->bounds().ToString()); + EXPECT_EQ("450,300 100x200", window3_->bounds().ToString()); +} + +// Assertions around attached window resizing (collapsing and expanding) with +// 3 windows. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3_Compress) { + window_->SetBounds(gfx::Rect( 100, 300, 200, 300)); + window2_->SetBounds(gfx::Rect(300, 300, 200, 200)); + window3_->SetBounds(gfx::Rect(450, 300, 100, 200)); + delegate2_.set_min_size(gfx::Size(52, 50)); + delegate3_.set_min_size(gfx::Size(38, 50)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + windows.push_back(window3_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it -100 to the right, which should collapse w1 and expand w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0); + EXPECT_EQ("100,300 100x300", window_->bounds().ToString()); + EXPECT_EQ("200,300 266x200", window2_->bounds().ToString()); + EXPECT_EQ("466,300 134x200", window3_->bounds().ToString()); + + // Move it 100 to the right. + resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0); + EXPECT_EQ("100,300 300x300", window_->bounds().ToString()); + EXPECT_EQ("400,300 200x200", window2_->bounds().ToString()); + EXPECT_EQ("600,300 100x200", window3_->bounds().ToString()); + + // 100 to the left again. + resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0); + EXPECT_EQ("100,300 100x300", window_->bounds().ToString()); + EXPECT_EQ("200,300 266x200", window2_->bounds().ToString()); + EXPECT_EQ("466,300 134x200", window3_->bounds().ToString()); +} + +// Assertions around collapsing and expanding from the bottom. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_Compress) { + window_->SetBounds(gfx::Rect( 0, 100, 400, 300)); + window2_->SetBounds(gfx::Rect(400, 400, 100, 200)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOM, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it up 100, which should expand w2 and collapse w1. + resizer->Drag(CalculateDragPoint(*resizer, 10, -100), 0); + EXPECT_EQ("0,100 400x200", window_->bounds().ToString()); + EXPECT_EQ("400,300 100x300", window2_->bounds().ToString()); + + // Collapse all the way to w1's min. + delegate_.set_min_size(gfx::Size(20, 20)); + resizer->Drag(CalculateDragPoint(*resizer, 20, -800), 0); + EXPECT_EQ("0,100 400x20", window_->bounds().ToString()); + EXPECT_EQ("400,120 100x480", window2_->bounds().ToString()); + + // Move 100 down. + resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0); + EXPECT_EQ("0,100 400x400", window_->bounds().ToString()); + EXPECT_EQ("400,500 100x100", window2_->bounds().ToString()); + + // Back to -100. + resizer->Drag(CalculateDragPoint(*resizer, 20, -100), 0); + EXPECT_EQ("0,100 400x200", window_->bounds().ToString()); + EXPECT_EQ("400,300 100x300", window2_->bounds().ToString()); +} + +// Assertions around attached window resize dragging from the bottom with 2 +// windows. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_2) { + window_->SetBounds(gfx::Rect( 0, 50, 400, 200)); + window2_->SetBounds(gfx::Rect(0, 250, 200, 100)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOM, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the bottom, which should expand w1 and push w2. + resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0); + EXPECT_EQ("0,50 400x300", window_->bounds().ToString()); + EXPECT_EQ("0,350 200x100", window2_->bounds().ToString()); + + // Push off the screen, w2 should be resized to its min. + delegate2_.set_min_size(gfx::Size(20, 20)); + resizer->Drag(CalculateDragPoint(*resizer, 50, 820), 0); + EXPECT_EQ("0,50 400x530", window_->bounds().ToString()); + EXPECT_EQ("0,580 200x20", window2_->bounds().ToString()); + + // Move back to 100 and verify w2 gets its original size. + resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0); + EXPECT_EQ("0,50 400x300", window_->bounds().ToString()); + EXPECT_EQ("0,350 200x100", window2_->bounds().ToString()); + + // Revert and make sure everything moves back. + resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0); + resizer->RevertDrag(); + EXPECT_EQ("0,50 400x200", window_->bounds().ToString()); + EXPECT_EQ("0,250 200x100", window2_->bounds().ToString()); +} + +#if defined(OS_WIN) +// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 +#define MAYBE_AttachedResize_BOTTOM_3 DISABLED_AttachedResize_BOTTOM_3 +#else +#define MAYBE_AttachedResize_BOTTOM_3 AttachedResize_BOTTOM_3 +#endif + +// Assertions around attached window resize dragging from the bottom with 3 +// windows. +TEST_F(WorkspaceWindowResizerTest, MAYBE_AttachedResize_BOTTOM_3) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets()); + + window_->SetBounds(gfx::Rect( 300, 100, 300, 200)); + window2_->SetBounds(gfx::Rect(300, 300, 200, 150)); + window3_->SetBounds(gfx::Rect(300, 450, 200, 100)); + delegate2_.set_min_size(gfx::Size(50, 52)); + delegate3_.set_min_size(gfx::Size(50, 38)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + windows.push_back(window3_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOM, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 down, which should expand w1 and push w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, -10, 100), 0); + EXPECT_EQ("300,100 300x300", window_->bounds().ToString()); + EXPECT_EQ("300,400 200x150", window2_->bounds().ToString()); + EXPECT_EQ("300,550 200x100", window3_->bounds().ToString()); + + // 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 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); + EXPECT_EQ("300,100 300x610", window_->bounds().ToString()); + EXPECT_EQ("300,710 200x52", window2_->bounds().ToString()); + EXPECT_EQ("300,762 200x38", window3_->bounds().ToString()); + + // Revert and make sure everything moves back. + resizer->RevertDrag(); + EXPECT_EQ("300,100 300x200", window_->bounds().ToString()); + EXPECT_EQ("300,300 200x150", window2_->bounds().ToString()); + EXPECT_EQ("300,450 200x100", window3_->bounds().ToString()); +} + +// Assertions around attached window resizing (collapsing and expanding) with +// 3 windows. +TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_3_Compress) { + window_->SetBounds(gfx::Rect( 0, 0, 200, 200)); + window2_->SetBounds(gfx::Rect(10, 200, 200, 200)); + window3_->SetBounds(gfx::Rect(20, 400, 100, 100)); + delegate2_.set_min_size(gfx::Size(52, 50)); + delegate3_.set_min_size(gfx::Size(38, 50)); + + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + windows.push_back(window3_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOM, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 up, which should collapse w1 and expand w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0); + EXPECT_EQ("0,0 200x100", window_->bounds().ToString()); + EXPECT_EQ("10,100 200x266", window2_->bounds().ToString()); + EXPECT_EQ("20,366 100x134", window3_->bounds().ToString()); + + // Move it 100 down. + resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0); + EXPECT_EQ("0,0 200x300", window_->bounds().ToString()); + EXPECT_EQ("10,300 200x200", window2_->bounds().ToString()); + EXPECT_EQ("20,500 100x100", window3_->bounds().ToString()); + + // 100 up again. + resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0); + EXPECT_EQ("0,0 200x100", window_->bounds().ToString()); + EXPECT_EQ("10,100 200x266", window2_->bounds().ToString()); + EXPECT_EQ("20,366 100x134", window3_->bounds().ToString()); +} + + +// Assertions around dragging to the left/right edge of the screen. +TEST_F(WorkspaceWindowResizerTest, Edge) { + int bottom = + ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).bottom(); + window_->SetBounds(gfx::Rect(20, 30, 50, 60)); + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 10), 0); + resizer->CompleteDrag(0); + EXPECT_EQ("0,0 720x" + base::IntToString(bottom), + window_->bounds().ToString()); + ASSERT_TRUE(GetRestoreBoundsInScreen(window_.get())); + EXPECT_EQ("20,30 50x60", + GetRestoreBoundsInScreen(window_.get())->ToString()); + } + // Try the same with the right side. + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); + resizer->CompleteDrag(0); + EXPECT_EQ("80,0 720x" + base::IntToString(bottom), + window_->bounds().ToString()); + ASSERT_TRUE(GetRestoreBoundsInScreen(window_.get())); + EXPECT_EQ("20,30 50x60", + GetRestoreBoundsInScreen(window_.get())->ToString()); + } + + // Test if the restore bounds is correct in multiple displays. + ClearRestoreBounds(window_.get()); + + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("800x600,200x600"); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + window_->SetBoundsInScreen(gfx::Rect(800, 10, 50, 60), + ScreenAsh::GetSecondaryDisplay()); + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + { + bottom = + ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).bottom(); + EXPECT_EQ("800,10 50x60", window_->GetBoundsInScreen().ToString()); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + + resizer->Drag(CalculateDragPoint(*resizer, 199, 00), 0); + resizer->CompleteDrag(0); + // With the resolution of 200x600 we will hit in this case the 50% screen + // size setting. + EXPECT_EQ("100,0 100x" + base::IntToString(bottom), + window_->bounds().ToString()); + EXPECT_EQ("800,10 50x60", + GetRestoreBoundsInScreen(window_.get())->ToString()); + } +} + +// Check that non resizable windows will not get resized. +TEST_F(WorkspaceWindowResizerTest, NonResizableWindows) { + window_->SetBounds(gfx::Rect(20, 30, 50, 60)); + window_->SetProperty(aura::client::kCanResizeKey, false); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -20, 0), 0); + resizer->CompleteDrag(0); + EXPECT_EQ("0,30 50x60", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, CancelSnapPhantom) { + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("800x600,800x600"); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(2U, root_windows.size()); + + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); + + // The pointer is on the edge but not shared. The snap phantom window + // controller should be non-NULL. + resizer->Drag(CalculateDragPoint(*resizer, 799, 0), 0); + EXPECT_TRUE(resizer->snap_phantom_window_controller_.get()); + + // Move the cursor across the edge. Now the snap phantom window controller + // should be canceled. + resizer->Drag(CalculateDragPoint(*resizer, 800, 0), 0); + EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); + } +} + +// Verifies windows are correctly restacked when reordering multiple windows. +TEST_F(WorkspaceWindowResizerTest, RestackAttached) { + window_->SetBounds(gfx::Rect( 0, 0, 200, 300)); + window2_->SetBounds(gfx::Rect(200, 0, 100, 200)); + window3_->SetBounds(gfx::Rect(300, 0, 100, 100)); + + { + std::vector<aura::Window*> windows; + windows.push_back(window2_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the right, which should expand w1 and push w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0); + + // 2 should be topmost since it's initially the highest in the stack. + EXPECT_EQ("2 1 3", WindowOrderAsString(window_->parent())); + } + + { + std::vector<aura::Window*> windows; + windows.push_back(window3_.get()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window2_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the right, which should expand w1 and push w2 and w3. + resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0); + + // 2 should be topmost since it's initially the highest in the stack. + EXPECT_EQ("2 3 1", WindowOrderAsString(window_->parent())); + } +} + +// Makes sure we don't allow dragging below the work area. +TEST_F(WorkspaceWindowResizerTest, DontDragOffBottom) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0)); + + ASSERT_EQ(1, Shell::GetScreen()->GetNumDisplays()); + + window_->SetBounds(gfx::Rect(100, 200, 300, 400)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0); + int expected_y = + kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10; + EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400", + window_->bounds().ToString()); +} + +// Makes sure we don't allow dragging on the work area with multidisplay. +TEST_F(WorkspaceWindowResizerTest, DontDragOffBottomWithMultiDisplay) { + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("800x600,800x600"); + ASSERT_EQ(2, Shell::GetScreen()->GetNumDisplays()); + + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0)); + + // Positions the secondary display at the bottom the primary display. + Shell::GetInstance()->display_controller()->SetLayoutForCurrentDisplays( + ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 0)); + + { + window_->SetBounds(gfx::Rect(100, 200, 300, 400)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 400), 0); + int expected_y = + kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10; + // When the mouse cursor is in the primary display, the window cannot move + // on non-work area with kMinOnscreenHeight margin. + EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400", + window_->bounds().ToString()); + } + + { + window_->SetBounds(gfx::Rect(100, 200, 300, 400)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0); + // The window can move to the secondary display beyond non-work area of + // the primary display. + EXPECT_EQ("100,800 300x400", window_->bounds().ToString()); + } +} + +// Makes sure we don't allow dragging off the top of the work area. +TEST_F(WorkspaceWindowResizerTest, DontDragOffTop) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(10, 0, 0, 0)); + + window_->SetBounds(gfx::Rect(100, 200, 300, 400)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, -600), 0); + EXPECT_EQ("100,10 300x400", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, ResizeBottomOutsideWorkArea) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + + window_->SetBounds(gfx::Rect(100, 200, 300, 380)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOP, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 8, 0), 0); + EXPECT_EQ("100,200 300x380", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideLeftWorkArea) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + int left = ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).x(); + int pixels_to_left_border = 50; + int window_width = 300; + int window_x = left - window_width + pixels_to_left_border; + window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(pixels_to_left_border, 0), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -window_width, 0), 0); + EXPECT_EQ(base::IntToString(window_x) + ",100 " + + base::IntToString(kMinimumOnScreenArea - window_x) + + "x380", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideRightWorkArea) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + int right = ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get()).right(); + int pixels_to_right_border = 50; + int window_width = 300; + int window_x = right - pixels_to_right_border; + window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(window_x, 0), HTLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0); + EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) + + ",100 " + + base::IntToString(window_width - pixels_to_right_border + + kMinimumOnScreenArea) + + "x380", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideBottomWorkArea) { + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + int bottom = ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get()).bottom(); + int delta_to_bottom = 50; + int height = 380; + window_->SetBounds(gfx::Rect(100, bottom - delta_to_bottom, 300, height)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(0, bottom - delta_to_bottom), HTTOP, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, bottom), 0); + EXPECT_EQ("100," + + base::IntToString(bottom - kMinimumOnScreenArea) + + " 300x" + + base::IntToString(height - (delta_to_bottom - + kMinimumOnScreenArea)), + window_->bounds().ToString()); +} + +// Verifies that 'outside' check of the resizer take into account the extended +// desktop in case of repositions. +TEST_F(WorkspaceWindowResizerTest, DragWindowOutsideRightToSecondaryDisplay) { + // Only primary display. Changes the window position to fit within the + // display. + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + int right = ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get()).right(); + int pixels_to_right_border = 50; + int window_width = 300; + int window_x = right - pixels_to_right_border; + window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(window_x, 0), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0); + EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) + + ",100 " + + base::IntToString(window_width) + + "x380", window_->bounds().ToString()); + + if (!SupportsMultipleDisplays()) + return; + + // With secondary display. Operation itself is same but doesn't change + // the position because the window is still within the secondary display. + UpdateDisplay("1000x600,600x400"); + Shell::GetInstance()->SetDisplayWorkAreaInsets( + Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0)); + window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380)); + resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0); + EXPECT_EQ(base::IntToString(window_x + window_width) + + ",100 " + + base::IntToString(window_width) + + "x380", window_->bounds().ToString()); +} + +// Verifies snapping to edges works. +TEST_F(WorkspaceWindowResizerTest, SnapToEdge) { + Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()-> + SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + // Click 50px to the right so that the mouse pointer does not leave the + // workspace ensuring sticky behavior. + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), + window_->bounds().origin() + gfx::Vector2d(50, 0), + HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Move to an x-coordinate of 15, which should not snap. + resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0); + // An x-coordinate of 7 should snap. + resizer->Drag(CalculateDragPoint(*resizer, 7 - 96, 0), 0); + EXPECT_EQ("0,112 320x160", window_->bounds().ToString()); + // Move to -15, should still snap to 0. + resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0); + EXPECT_EQ("0,112 320x160", window_->bounds().ToString()); + // At -32 should move past snap points. + resizer->Drag(CalculateDragPoint(*resizer, -32 - 96, 0), 0); + EXPECT_EQ("-32,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, -33 - 96, 0), 0); + EXPECT_EQ("-33,112 320x160", window_->bounds().ToString()); + + // Right side should similarly snap. + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 15, 0), 0); + EXPECT_EQ("465,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 7, 0), 0); + EXPECT_EQ("480,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 15, 0), 0); + EXPECT_EQ("480,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 32, 0), 0); + EXPECT_EQ("512,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 33, 0), 0); + EXPECT_EQ("513,112 320x160", window_->bounds().ToString()); + + // And the bottom should snap too. + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 - 7), 0); + EXPECT_EQ("96,437 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 + 15), 0); + EXPECT_EQ("96,437 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 32), 0); + EXPECT_EQ("96,470 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 33), 0); + EXPECT_EQ("96,471 320x160", window_->bounds().ToString()); + + // And the top should snap too. + resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 20), 0); + EXPECT_EQ("96,20 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 7), 0); + EXPECT_EQ("96,0 320x160", window_->bounds().ToString()); + // No need to test dragging < 0 as we force that to 0. +} + +// Verifies a resize snap when dragging TOPLEFT. +TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -98, -199), 0); + EXPECT_EQ("0,0 120x230", window_->bounds().ToString()); +} + +// Verifies a resize snap when dragging TOPRIGHT. +TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag( + CalculateDragPoint(*resizer, work_area.right() - 120 - 1, -199), 0); + EXPECT_EQ(100, window_->bounds().x()); + EXPECT_EQ(work_area.y(), window_->bounds().y()); + EXPECT_EQ(work_area.right() - 100, window_->bounds().width()); + EXPECT_EQ(230, window_->bounds().height()); +} + +// Verifies a resize snap when dragging BOTTOMRIGHT. +TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag( + CalculateDragPoint(*resizer, work_area.right() - 120 - 1, + work_area.bottom() - 220 - 2), 0); + EXPECT_EQ(100, window_->bounds().x()); + EXPECT_EQ(200, window_->bounds().y()); + EXPECT_EQ(work_area.right() - 100, window_->bounds().width()); + EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height()); +} + +// Verifies a resize snap when dragging BOTTOMLEFT. +TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag( + CalculateDragPoint(*resizer, -98, work_area.bottom() - 220 - 2), 0); + EXPECT_EQ(0, window_->bounds().x()); + EXPECT_EQ(200, window_->bounds().y()); + EXPECT_EQ(120, window_->bounds().width()); + EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height()); +} + +// Verifies sticking to edges works. +TEST_F(WorkspaceWindowResizerTestSticky, StickToEdge) { + Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()-> + SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + // Click 50px to the right so that the mouse pointer does not leave the + // workspace ensuring sticky behavior. + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), + window_->bounds().origin() + gfx::Vector2d(50, 0), + HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Move to an x-coordinate of 15, which should not stick. + resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0); + // Move to -15, should still stick to 0. + resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0); + EXPECT_EQ("0,112 320x160", window_->bounds().ToString()); + // At -100 should move past edge. + resizer->Drag(CalculateDragPoint(*resizer, -100 - 96, 0), 0); + EXPECT_EQ("-100,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, -101 - 96, 0), 0); + EXPECT_EQ("-101,112 320x160", window_->bounds().ToString()); + + // Right side should similarly stick. + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 15, 0), 0); + EXPECT_EQ("465,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 15, 0), 0); + EXPECT_EQ("480,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 100, 0), 0); + EXPECT_EQ("580,112 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 101, 0), 0); + EXPECT_EQ("581,112 320x160", window_->bounds().ToString()); + + // And the bottom should stick too. + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 + 15), 0); + EXPECT_EQ("96,437 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 100), 0); + EXPECT_EQ("96,538 320x160", window_->bounds().ToString()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 101), 0); + EXPECT_EQ("96,539 320x160", window_->bounds().ToString()); + + // No need to test dragging < 0 as we force that to 0. +} + +// Verifies not sticking to edges when a mouse pointer is outside of work area. +TEST_F(WorkspaceWindowResizerTestSticky, NoStickToEdgeWhenOutside) { + Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()-> + SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Move to an x-coordinate of 15, which should not stick. + resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0); + // Move to -15, should still stick to 0. + resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0); + EXPECT_EQ("-15,112 320x160", window_->bounds().ToString()); +} + +// Verifies a resize sticks when dragging TOPLEFT. +TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_TOPLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -15 - 100, -15 -200), 0); + EXPECT_EQ("0,0 120x230", window_->bounds().ToString()); +} + +// Verifies a resize sticks when dragging TOPRIGHT. +TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_TOPRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, work_area.right() - 100 + 20, + -200 - 15), 0); + EXPECT_EQ(100, window_->bounds().x()); + EXPECT_EQ(work_area.y(), window_->bounds().y()); + EXPECT_EQ(work_area.right() - 100, window_->bounds().width()); + EXPECT_EQ(230, window_->bounds().height()); +} + +// Verifies a resize snap when dragging BOTTOMRIGHT. +TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_BOTTOMRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, work_area.right() - 100 - 20 + 15, + work_area.bottom() - 200 - 30 + 15), 0); + EXPECT_EQ(100, window_->bounds().x()); + EXPECT_EQ(200, window_->bounds().y()); + EXPECT_EQ(work_area.right() - 100, window_->bounds().width()); + EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height()); +} + +// Verifies a resize snap when dragging BOTTOMLEFT. +TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_BOTTOMLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -15 - 100, + work_area.bottom() - 200 - 30 + 15), 0); + EXPECT_EQ(0, window_->bounds().x()); + EXPECT_EQ(200, window_->bounds().y()); + EXPECT_EQ(120, window_->bounds().width()); + EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height()); +} + +TEST_F(WorkspaceWindowResizerTest, CtrlDragResizeToExactPosition) { + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Resize the right bottom to add 10 in width, 12 in height. + resizer->Drag(CalculateDragPoint(*resizer, 10, 12), ui::EF_CONTROL_DOWN); + // Both bottom and right sides to resize to exact size requested. + EXPECT_EQ("96,112 330x172", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, CtrlCompleteDragMoveToExactPosition) { + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Ctrl + drag the window to new poistion by adding (10, 12) to its origin, + // the window should move to the exact position. + resizer->Drag(CalculateDragPoint(*resizer, 10, 12), 0); + resizer->CompleteDrag(ui::EF_CONTROL_DOWN); + EXPECT_EQ("106,124 320x160", window_->bounds().ToString()); +} + +// Check that only usable sizes get returned by the resizer. +TEST_F(WorkspaceWindowResizerTest, TestProperSizerResolutions) { + // Check that we have the correct work area resolution which fits our + // expected test result. + gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( + window_.get())); + EXPECT_EQ(800, work_area.width()); + + window_->SetBounds(gfx::Rect(96, 112, 320, 160)); + scoped_ptr<SnapSizer> resizer(new SnapSizer( + window_.get(), + gfx::Point(), + SnapSizer::LEFT_EDGE, + SnapSizer::OTHER_INPUT)); + ASSERT_TRUE(resizer.get()); + shelf_layout_manager()->SetAutoHideBehavior( + SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + + // Check that the list is declining and contains elements of the + // ideal size list [1280, 1024, 768, 640] as well as 50% and 90% the work + // area. + gfx::Rect rect = resizer->GetTargetBoundsForSize(0); + EXPECT_EQ("0,0 720x597", rect.ToString()); + rect = resizer->GetTargetBoundsForSize(1); + EXPECT_EQ("0,0 640x597", rect.ToString()); + rect = resizer->GetTargetBoundsForSize(2); + EXPECT_EQ("0,0 400x597", rect.ToString()); + shelf_layout_manager()->SetAutoHideBehavior( + SHELF_AUTO_HIDE_BEHAVIOR_NEVER); + rect = resizer->GetTargetBoundsForSize(0); + EXPECT_EQ("0,0 720x552", rect.ToString()); + rect = resizer->GetTargetBoundsForSize(1); + EXPECT_EQ("0,0 640x552", rect.ToString()); + rect = resizer->GetTargetBoundsForSize(2); + EXPECT_EQ("0,0 400x552", rect.ToString()); +} + +// Verifies that a dragged window will restore to its pre-maximized size. +TEST_F(WorkspaceWindowResizerTest, RestoreToPreMaximizeCoordinates) { + window_->SetBounds(gfx::Rect(0, 0, 1000, 1000)); + SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Drag the window to new position by adding (10, 10) to original point, + // the window should get restored. + resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0); + resizer->CompleteDrag(0); + EXPECT_EQ("10,10 320x160", window_->bounds().ToString()); + // The restore rectangle should get cleared as well. + EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window_.get())); +} + +// Verifies that a dragged window will restore to its pre-maximized size. +TEST_F(WorkspaceWindowResizerTest, RevertResizeOperation) { + const gfx::Rect initial_bounds(0, 0, 200, 400); + window_->SetBounds(initial_bounds); + SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Drag the window to new poistion by adding (180, 16) to original point, + // the window should get restored. + resizer->Drag(CalculateDragPoint(*resizer, 180, 16), 0); + resizer->RevertDrag(); + EXPECT_EQ(initial_bounds.ToString(), window_->bounds().ToString()); + EXPECT_EQ("96,112 320x160", + GetRestoreBoundsInScreen(window_.get())->ToString()); +} + +// Check that only usable sizes get returned by the resizer. +TEST_F(WorkspaceWindowResizerTest, MagneticallyAttach) { + window_->SetBounds(gfx::Rect(10, 10, 20, 30)); + window2_->SetBounds(gfx::Rect(150, 160, 25, 20)); + window2_->Show(); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Move |window| one pixel to the left of |window2|. Should snap to right and + // top. + resizer->Drag(CalculateDragPoint(*resizer, 119, 145), 0); + EXPECT_EQ("130,160 20x30", window_->bounds().ToString()); + + // Move |window| one pixel to the right of |window2|. Should snap to left and + // top. + resizer->Drag(CalculateDragPoint(*resizer, 164, 145), 0); + EXPECT_EQ("175,160 20x30", window_->bounds().ToString()); + + // Move |window| one pixel above |window2|. Should snap to top and left. + resizer->Drag(CalculateDragPoint(*resizer, 142, 119), 0); + EXPECT_EQ("150,130 20x30", window_->bounds().ToString()); + + // Move |window| one pixel above the bottom of |window2|. Should snap to + // bottom and left. + resizer->Drag(CalculateDragPoint(*resizer, 142, 169), 0); + EXPECT_EQ("150,180 20x30", window_->bounds().ToString()); +} + +// The following variants verify magnetic snapping during resize when dragging a +// particular edge. +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOP) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->SetBounds(gfx::Rect(99, 179, 10, 20)); + window2_->Show(); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOP, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,199 20x31", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->SetBounds(gfx::Rect(99, 179, 10, 20)); + window2_->Show(); + + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("99,199 21x31", window_->bounds().ToString()); + resizer->RevertDrag(); + } + + { + window2_->SetBounds(gfx::Rect(88, 201, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("98,201 22x29", window_->bounds().ToString()); + resizer->RevertDrag(); + } +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->Show(); + + { + window2_->SetBounds(gfx::Rect(111, 179, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,199 21x31", window_->bounds().ToString()); + resizer->RevertDrag(); + } + + { + window2_->SetBounds(gfx::Rect(121, 199, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTTOPRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,199 21x31", window_->bounds().ToString()); + resizer->RevertDrag(); + } +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_RIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->SetBounds(gfx::Rect(121, 199, 10, 20)); + window2_->Show(); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,200 21x30", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMRIGHT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->Show(); + + { + window2_->SetBounds(gfx::Rect(122, 212, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,200 22x32", window_->bounds().ToString()); + resizer->RevertDrag(); + } + + { + window2_->SetBounds(gfx::Rect(111, 233, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,200 21x33", window_->bounds().ToString()); + resizer->RevertDrag(); + } +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOM) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->SetBounds(gfx::Rect(111, 233, 10, 20)); + window2_->Show(); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOM, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("100,200 20x33", window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMLEFT) { + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->Show(); + + { + window2_->SetBounds(gfx::Rect(99, 231, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("99,200 21x31", window_->bounds().ToString()); + resizer->RevertDrag(); + } + + { + window2_->SetBounds(gfx::Rect(89, 209, 10, 20)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("99,200 21x29", window_->bounds().ToString()); + resizer->RevertDrag(); + } +} + +TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_LEFT) { + window2_->SetBounds(gfx::Rect(89, 209, 10, 20)); + window_->SetBounds(gfx::Rect(100, 200, 20, 30)); + window2_->Show(); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTLEFT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0); + EXPECT_EQ("99,200 21x30", window_->bounds().ToString()); +} + +// Test that the user user moved window flag is getting properly set. +TEST_F(WorkspaceWindowResizerTest, CheckUserWindowMangedFlags) { + window_->SetBounds(gfx::Rect( 0, 50, 400, 200)); + + std::vector<aura::Window*> no_attached_windows; + // Check that an abort doesn't change anything. + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, no_attached_windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the bottom. + resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0); + EXPECT_EQ("0,150 400x200", window_->bounds().ToString()); + resizer->RevertDrag(); + + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window_.get())); + } + + // Check that a completed move / size does change the user coordinates. + { + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, no_attached_windows)); + ASSERT_TRUE(resizer.get()); + // Move it 100 to the bottom. + resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0); + EXPECT_EQ("0,150 400x200", window_->bounds().ToString()); + resizer->CompleteDrag(0); + EXPECT_TRUE(ash::wm::HasUserChangedWindowPositionOrSize(window_.get())); + } +} + +// Test that a window with a specified max size doesn't exceed it when dragged. +TEST_F(WorkspaceWindowResizerTest, TestMaxSizeEnforced) { + window_->SetBounds(gfx::Rect(0, 0, 400, 300)); + delegate_.set_max_size(gfx::Size(401, 301)); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0); + EXPECT_EQ(401, window_->bounds().width()); + EXPECT_EQ(301, window_->bounds().height()); +} + +// Test that a window with a specified max width doesn't restrict its height. +TEST_F(WorkspaceWindowResizerTest, TestPartialMaxSizeEnforced) { + window_->SetBounds(gfx::Rect(0, 0, 400, 300)); + delegate_.set_max_size(gfx::Size(401, 0)); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTBOTTOMRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0); + EXPECT_EQ(401, window_->bounds().width()); + EXPECT_EQ(302, window_->bounds().height()); +} + +// Test that a window with a specified max size can't be snapped. +TEST_F(WorkspaceWindowResizerTest, PhantomSnapMaxSize) { + { + // With max size not set we get a phantom window controller for dragging off + // the right hand side. + window_->SetBounds(gfx::Rect(0, 0, 300, 200)); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); + resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0); + EXPECT_TRUE(resizer->snap_phantom_window_controller_.get()); + } + { + // With max size defined, we get no phantom window. + window_->SetBounds(gfx::Rect(0, 0, 300, 200)); + delegate_.set_max_size(gfx::Size(300, 200)); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0); + EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); + } +} + +TEST_F(WorkspaceWindowResizerTest, DontRewardRightmostWindowForOverflows) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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()); +} + +#if defined(OS_WIN) +// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 +#define MAYBE_DontExceedMinHeight DISABLED_DontExceedMinHeight +#else +#define MAYBE_DontExceedMinHeight DontExceedMinHeight +#endif + +TEST_F(WorkspaceWindowResizerTest, MAYBE_DontExceedMinHeight) { + UpdateDisplay("600x500"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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, MoveAttachedWhenGrownToMaxSize) { + UpdateDisplay("600x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows)); + ASSERT_TRUE(resizer.get()); + // Move it 52 to the left, which should contract w1 and expand and move w2-3. + 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()); +} + +#if defined(OS_WIN) +// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 +#define MAYBE_MainWindowHonoursMaxWidth DISABLED_MainWindowHonoursMaxWidth +#else +#define MAYBE_MainWindowHonoursMaxWidth MainWindowHonoursMaxWidth +#endif + +TEST_F(WorkspaceWindowResizerTest, MAYBE_MainWindowHonoursMaxWidth) { + UpdateDisplay("400x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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) { + UpdateDisplay("400x800"); + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + 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()); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTRIGHT, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, 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()); +} + +// The following variants test that windows are resized correctly to the edges +// of the screen using touch, when touch point is off of the window border. +TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_RIGHT) { + shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + + InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTRIGHT); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + + aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + touch_resize_window_.get()); + + // Drag out of the right border a bit and check if the border is aligned with + // the touch point. + generator.GestureScrollSequence(gfx::Point(715, kRootHeight / 2), + gfx::Point(725, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 625, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag more, but stop before being snapped to the edge. + generator.GestureScrollSequence(gfx::Point(725, kRootHeight / 2), + gfx::Point(760, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 660, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag even more to snap to the edge. + generator.GestureScrollSequence(gfx::Point(760, kRootHeight / 2), + gfx::Point(775, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 700, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_LEFT) { + shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + + InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTLEFT); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + + aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + touch_resize_window_.get()); + + // Drag out of the left border a bit and check if the border is aligned with + // the touch point. + generator.GestureScrollSequence(gfx::Point(85, kRootHeight / 2), + gfx::Point(75, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(75, 100, 625, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag more, but stop before being snapped to the edge. + generator.GestureScrollSequence(gfx::Point(75, kRootHeight / 2), + gfx::Point(40, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(40, 100, 660, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag even more to snap to the edge. + generator.GestureScrollSequence(gfx::Point(40, kRootHeight / 2), + gfx::Point(25, kRootHeight / 2), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(0, 100, 700, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_TOP) { + shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + + InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTTOP); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + + aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + touch_resize_window_.get()); + + // Drag out of the top border a bit and check if the border is aligned with + // the touch point. + generator.GestureScrollSequence(gfx::Point(400, 85), + gfx::Point(400, 75), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 75, 600, kRootHeight - 175).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag more, but stop before being snapped to the edge. + generator.GestureScrollSequence(gfx::Point(400, 75), + gfx::Point(400, 40), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 40, 600, kRootHeight - 140).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag even more to snap to the edge. + generator.GestureScrollSequence(gfx::Point(400, 40), + gfx::Point(400, 25), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 0, 600, kRootHeight - 100).ToString(), + touch_resize_window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_BOTTOM) { + shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + + InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTBOTTOM); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(), + touch_resize_window_->bounds().ToString()); + + aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + touch_resize_window_.get()); + + // Drag out of the bottom border a bit and check if the border is aligned with + // the touch point. + generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 85), + gfx::Point(400, kRootHeight - 75), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 175).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag more, but stop before being snapped to the edge. + generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 75), + gfx::Point(400, kRootHeight - 40), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 140).ToString(), + touch_resize_window_->bounds().ToString()); + // Drag even more to snap to the edge. + generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 40), + gfx::Point(400, kRootHeight - 25), + base::TimeDelta::FromMilliseconds(100), + 1); + EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 100).ToString(), + touch_resize_window_->bounds().ToString()); +} + +TEST_F(WorkspaceWindowResizerTest, PhantomWindowShow) { + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("500x400,500x400"); + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows())); + ASSERT_TRUE(resizer.get()); + EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); + + // The pointer is on the edge but not shared. The snap phantom window + // controller should be non-NULL. + resizer->Drag(CalculateDragPoint(*resizer, 499, 0), 0); + EXPECT_TRUE(resizer->snap_phantom_window_controller_.get()); + PhantomWindowController* phantom_controller( + resizer->snap_phantom_window_controller_.get()); + + // phantom widget only in the left screen. + phantom_controller->Show(gfx::Rect(100, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_FALSE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + + // Move phantom widget into the right screen. Test that 2 widgets got created. + phantom_controller->Show(gfx::Rect(600, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_TRUE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[1], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_start_->GetNativeWindow()-> + GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Move phantom widget only in the right screen. Start widget should close. + phantom_controller->Show(gfx::Rect(700, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_FALSE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[1], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Move phantom widget into the left screen. Start widget should open. + phantom_controller->Show(gfx::Rect(100, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_TRUE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ( + root_windows[1], + phantom_controller->phantom_widget_start_->GetNativeWindow()-> + GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Move phantom widget while in the left screen. Start widget should close. + phantom_controller->Show(gfx::Rect(200, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_FALSE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Move phantom widget spanning both screens with most of the window in the + // right screen. Two widgets are created. + phantom_controller->Show(gfx::Rect(495, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_TRUE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[1], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_start_->GetNativeWindow()-> + GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Move phantom widget back into the left screen. Phantom widgets should swap. + phantom_controller->Show(gfx::Rect(200, 100, 50, 60)); + EXPECT_TRUE(phantom_controller->phantom_widget_); + EXPECT_TRUE(phantom_controller->phantom_widget_start_); + EXPECT_EQ( + root_windows[0], + phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ( + root_windows[1], + phantom_controller->phantom_widget_start_->GetNativeWindow()-> + GetRootWindow()); + RunAnimationTillComplete(phantom_controller->animation_.get()); + + // Hide phantom controller. Both widgets should close. + phantom_controller->Hide(); + EXPECT_FALSE(phantom_controller->phantom_widget_); + EXPECT_FALSE(phantom_controller->phantom_widget_start_); +} + +} // namespace internal +} // namespace ash |