1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ash/wm/workspace/multi_window_resize_controller.h" 6 7#include "ash/shell.h" 8#include "ash/test/ash_test_base.h" 9#include "ash/test/shell_test_api.h" 10#include "ash/wm/window_util.h" 11#include "ash/wm/workspace_controller.h" 12#include "ash/wm/workspace_controller_test_helper.h" 13#include "ash/wm/workspace/workspace_event_handler_test_helper.h" 14#include "ui/aura/test/event_generator.h" 15#include "ui/aura/test/test_window_delegate.h" 16#include "ui/aura/window.h" 17#include "ui/base/hit_test.h" 18#include "ui/gfx/screen.h" 19#include "ui/views/widget/widget.h" 20 21namespace ash { 22 23class MultiWindowResizeControllerTest : public test::AshTestBase { 24 public: 25 MultiWindowResizeControllerTest() : resize_controller_(NULL) {} 26 virtual ~MultiWindowResizeControllerTest() {} 27 28 virtual void SetUp() OVERRIDE { 29 test::AshTestBase::SetUp(); 30 WorkspaceController* wc = 31 test::ShellTestApi(Shell::GetInstance()).workspace_controller(); 32 WorkspaceEventHandler* event_handler = 33 WorkspaceControllerTestHelper(wc).GetEventHandler(); 34 resize_controller_ = WorkspaceEventHandlerTestHelper(event_handler). 35 resize_controller(); 36 } 37 38 protected: 39 aura::Window* CreateTestWindow(aura::WindowDelegate* delegate, 40 const gfx::Rect& bounds) { 41 aura::Window* window = new aura::Window(delegate); 42 window->SetType(ui::wm::WINDOW_TYPE_NORMAL); 43 window->Init(aura::WINDOW_LAYER_TEXTURED); 44 ParentWindowInPrimaryRootWindow(window); 45 window->SetBounds(bounds); 46 window->Show(); 47 return window; 48 } 49 50 void ShowNow() { 51 resize_controller_->ShowNow(); 52 } 53 54 bool IsShowing() { 55 return resize_controller_->IsShowing(); 56 } 57 58 bool HasPendingShow() { 59 return resize_controller_->show_timer_.IsRunning(); 60 } 61 62 bool HasPendingHide() { 63 return resize_controller_->hide_timer_.IsRunning(); 64 } 65 66 void Hide() { 67 resize_controller_->Hide(); 68 } 69 70 bool HasTarget(aura::Window* window) { 71 if (!resize_controller_->windows_.is_valid()) 72 return false; 73 if ((resize_controller_->windows_.window1 == window || 74 resize_controller_->windows_.window2 == window)) 75 return true; 76 for (size_t i = 0; 77 i < resize_controller_->windows_.other_windows.size(); ++i) { 78 if (resize_controller_->windows_.other_windows[i] == window) 79 return true; 80 } 81 return false; 82 } 83 84 bool IsOverWindows(const gfx::Point& loc) { 85 return resize_controller_->IsOverWindows(loc); 86 } 87 88 views::Widget* resize_widget() { 89 return resize_controller_->resize_widget_.get(); 90 } 91 92 MultiWindowResizeController* resize_controller_; 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(MultiWindowResizeControllerTest); 96}; 97 98// Assertions around moving mouse over 2 windows. 99TEST_F(MultiWindowResizeControllerTest, BasicTests) { 100 aura::test::TestWindowDelegate delegate1; 101 scoped_ptr<aura::Window> w1( 102 CreateTestWindow(&delegate1, gfx::Rect(0, 0, 100, 100))); 103 delegate1.set_window_component(HTRIGHT); 104 aura::test::TestWindowDelegate delegate2; 105 scoped_ptr<aura::Window> w2( 106 CreateTestWindow(&delegate2, gfx::Rect(100, 0, 100, 100))); 107 delegate2.set_window_component(HTRIGHT); 108 aura::test::EventGenerator generator(w1->GetRootWindow()); 109 generator.MoveMouseTo(w1->bounds().CenterPoint()); 110 EXPECT_TRUE(HasPendingShow()); 111 EXPECT_TRUE(IsShowing()); 112 EXPECT_FALSE(HasPendingHide()); 113 114 // Force a show now. 115 ShowNow(); 116 EXPECT_FALSE(HasPendingShow()); 117 EXPECT_TRUE(IsShowing()); 118 EXPECT_FALSE(HasPendingHide()); 119 120 EXPECT_FALSE(IsOverWindows(gfx::Point(200, 200))); 121 122 // Have to explicitly invoke this as MouseWatcher listens for native events. 123 resize_controller_->MouseMovedOutOfHost(); 124 EXPECT_FALSE(HasPendingShow()); 125 EXPECT_FALSE(IsShowing()); 126 EXPECT_FALSE(HasPendingHide()); 127} 128 129// Makes sure deleting a window hides. 130TEST_F(MultiWindowResizeControllerTest, DeleteWindow) { 131 aura::test::TestWindowDelegate delegate1; 132 scoped_ptr<aura::Window> w1( 133 CreateTestWindow(&delegate1, gfx::Rect(0, 0, 100, 100))); 134 delegate1.set_window_component(HTRIGHT); 135 aura::test::TestWindowDelegate delegate2; 136 scoped_ptr<aura::Window> w2( 137 CreateTestWindow(&delegate2, gfx::Rect(100, 0, 100, 100))); 138 delegate2.set_window_component(HTRIGHT); 139 aura::test::EventGenerator generator(w1->GetRootWindow()); 140 generator.MoveMouseTo(w1->bounds().CenterPoint()); 141 EXPECT_TRUE(HasPendingShow()); 142 EXPECT_TRUE(IsShowing()); 143 EXPECT_FALSE(HasPendingHide()); 144 145 // Force a show now. 146 ShowNow(); 147 EXPECT_FALSE(HasPendingShow()); 148 EXPECT_TRUE(IsShowing()); 149 EXPECT_FALSE(HasPendingHide()); 150 151 // Move the mouse over the resize widget. 152 ASSERT_TRUE(resize_widget()); 153 gfx::Rect bounds(resize_widget()->GetWindowBoundsInScreen()); 154 generator.MoveMouseTo(bounds.x() + 1, bounds.y() + 1); 155 EXPECT_FALSE(HasPendingShow()); 156 EXPECT_TRUE(IsShowing()); 157 EXPECT_FALSE(HasPendingHide()); 158 159 // Move the resize widget 160 generator.PressLeftButton(); 161 generator.MoveMouseTo(bounds.x() + 10, bounds.y() + 10); 162 163 // Delete w2. 164 w2.reset(); 165 EXPECT_TRUE(resize_widget() == NULL); 166 EXPECT_FALSE(HasPendingShow()); 167 EXPECT_FALSE(IsShowing()); 168 EXPECT_FALSE(HasPendingHide()); 169 EXPECT_FALSE(HasTarget(w1.get())); 170} 171 172// Tests resizing. 173TEST_F(MultiWindowResizeControllerTest, Drag) { 174 aura::test::TestWindowDelegate delegate1; 175 scoped_ptr<aura::Window> w1( 176 CreateTestWindow(&delegate1, gfx::Rect(0, 0, 100, 100))); 177 delegate1.set_window_component(HTRIGHT); 178 aura::test::TestWindowDelegate delegate2; 179 scoped_ptr<aura::Window> w2( 180 CreateTestWindow(&delegate2, gfx::Rect(100, 0, 100, 100))); 181 delegate2.set_window_component(HTRIGHT); 182 aura::test::EventGenerator generator(w1->GetRootWindow()); 183 generator.MoveMouseTo(w1->bounds().CenterPoint()); 184 EXPECT_TRUE(HasPendingShow()); 185 EXPECT_TRUE(IsShowing()); 186 EXPECT_FALSE(HasPendingHide()); 187 188 // Force a show now. 189 ShowNow(); 190 EXPECT_FALSE(HasPendingShow()); 191 EXPECT_TRUE(IsShowing()); 192 EXPECT_FALSE(HasPendingHide()); 193 194 // Move the mouse over the resize widget. 195 ASSERT_TRUE(resize_widget()); 196 gfx::Rect bounds(resize_widget()->GetWindowBoundsInScreen()); 197 generator.MoveMouseTo(bounds.x() + 1, bounds.y() + 1); 198 EXPECT_FALSE(HasPendingShow()); 199 EXPECT_TRUE(IsShowing()); 200 EXPECT_FALSE(HasPendingHide()); 201 202 // Move the resize widget 203 generator.PressLeftButton(); 204 generator.MoveMouseTo(bounds.x() + 11, bounds.y() + 10); 205 generator.ReleaseLeftButton(); 206 207 EXPECT_TRUE(resize_widget()); 208 EXPECT_FALSE(HasPendingShow()); 209 EXPECT_TRUE(IsShowing()); 210 EXPECT_FALSE(HasPendingHide()); 211 EXPECT_EQ("0,0 110x100", w1->bounds().ToString()); 212 EXPECT_EQ("110,0 100x100", w2->bounds().ToString()); 213} 214 215// Makes sure three windows are picked up. 216TEST_F(MultiWindowResizeControllerTest, Three) { 217 aura::test::TestWindowDelegate delegate1; 218 scoped_ptr<aura::Window> w1( 219 CreateTestWindow(&delegate1, gfx::Rect(0, 0, 100, 100))); 220 delegate1.set_window_component(HTRIGHT); 221 aura::test::TestWindowDelegate delegate2; 222 scoped_ptr<aura::Window> w2( 223 CreateTestWindow(&delegate2, gfx::Rect(100, 0, 100, 100))); 224 delegate2.set_window_component(HTRIGHT); 225 aura::test::TestWindowDelegate delegate3; 226 scoped_ptr<aura::Window> w3( 227 CreateTestWindow(&delegate3, gfx::Rect(200, 0, 100, 100))); 228 delegate3.set_window_component(HTRIGHT); 229 230 aura::test::EventGenerator generator(w1->GetRootWindow()); 231 generator.MoveMouseTo(w1->bounds().CenterPoint()); 232 EXPECT_TRUE(HasPendingShow()); 233 EXPECT_TRUE(IsShowing()); 234 EXPECT_FALSE(HasPendingHide()); 235 EXPECT_FALSE(HasTarget(w3.get())); 236 237 ShowNow(); 238 EXPECT_FALSE(HasPendingShow()); 239 EXPECT_TRUE(IsShowing()); 240 EXPECT_FALSE(HasPendingHide()); 241 242 // w3 should be picked up when resize is started. 243 gfx::Rect bounds(resize_widget()->GetWindowBoundsInScreen()); 244 generator.MoveMouseTo(bounds.x() + 1, bounds.y() + 1); 245 generator.PressLeftButton(); 246 generator.MoveMouseTo(bounds.x() + 11, bounds.y() + 10); 247 248 EXPECT_TRUE(HasTarget(w3.get())); 249 250 // Release the mouse. The resizer should still be visible and a subsequent 251 // press should not trigger a DCHECK. 252 generator.ReleaseLeftButton(); 253 EXPECT_TRUE(IsShowing()); 254 generator.PressLeftButton(); 255} 256 257} // namespace ash 258