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