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.
5 #include "ash/wm/toplevel_window_event_handler.h"
7 #include "ash/root_window_controller.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/test/ash_test_base.h"
11 #include "ash/wm/resize_shadow.h"
12 #include "ash/wm/resize_shadow_controller.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/workspace_controller.h"
16 #include "base/basictypes.h"
17 #include "base/compiler_specific.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "ui/aura/client/aura_constants.h"
22 #include "ui/aura/test/aura_test_base.h"
23 #include "ui/aura/test/test_window_delegate.h"
24 #include "ui/aura/window_event_dispatcher.h"
25 #include "ui/base/hit_test.h"
26 #include "ui/events/event.h"
27 #include "ui/events/test/event_generator.h"
28 #include "ui/gfx/screen.h"
29 #include "ui/wm/core/window_util.h"
30 #include "ui/wm/public/window_move_client.h"
33 // Windows headers define macros for these function names which screw with us.
34 #if defined(CreateWindow)
44 // A simple window delegate that returns the specified hit-test code when
45 // requested and applies a minimum size constraint if there is one.
46 class TestWindowDelegate
: public aura::test::TestWindowDelegate
{
48 explicit TestWindowDelegate(int hittest_code
) {
49 set_window_component(hittest_code
);
51 ~TestWindowDelegate() override
{}
54 // Overridden from aura::Test::TestWindowDelegate:
55 void OnWindowDestroyed(aura::Window
* window
) override
{ delete this; }
57 DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate
);
60 class ToplevelWindowEventHandlerTest
: public AshTestBase
{
62 ToplevelWindowEventHandlerTest() {}
63 ~ToplevelWindowEventHandlerTest() override
{}
66 aura::Window
* CreateWindow(int hittest_code
) {
67 TestWindowDelegate
* d1
= new TestWindowDelegate(hittest_code
);
68 aura::Window
* w1
= new aura::Window(d1
);
69 w1
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
71 w1
->Init(ui::LAYER_TEXTURED
);
72 aura::Window
* parent
= Shell::GetContainer(
73 Shell::GetPrimaryRootWindow(), kShellWindowId_AlwaysOnTopContainer
);
75 w1
->SetBounds(gfx::Rect(0, 0, 100, 100));
80 void DragFromCenterBy(aura::Window
* window
, int dx
, int dy
) {
81 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(), window
);
82 generator
.DragMouseBy(dx
, dy
);
85 void TouchDragFromCenterBy(aura::Window
* window
, int dx
, int dy
) {
86 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(), window
);
87 generator
.PressMoveAndReleaseTouchBy(dx
, dy
);
90 scoped_ptr
<ToplevelWindowEventHandler
> handler_
;
93 DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventHandlerTest
);
98 TEST_F(ToplevelWindowEventHandlerTest
, Caption
) {
99 scoped_ptr
<aura::Window
> w1(CreateWindow(HTCAPTION
));
100 gfx::Size size
= w1
->bounds().size();
101 DragFromCenterBy(w1
.get(), 100, 100);
102 // Position should have been offset by 100,100.
103 EXPECT_EQ("100,100", w1
->bounds().origin().ToString());
104 // Size should not have.
105 EXPECT_EQ(size
.ToString(), w1
->bounds().size().ToString());
107 TouchDragFromCenterBy(w1
.get(), 100, 100);
108 // Position should have been offset by 100,100.
109 EXPECT_EQ("200,200", w1
->bounds().origin().ToString());
110 // Size should not have.
111 EXPECT_EQ(size
.ToString(), w1
->bounds().size().ToString());
114 TEST_F(ToplevelWindowEventHandlerTest
, BottomRight
) {
115 scoped_ptr
<aura::Window
> w1(CreateWindow(HTBOTTOMRIGHT
));
116 gfx::Point position
= w1
->bounds().origin();
117 DragFromCenterBy(w1
.get(), 100, 100);
118 // Position should not have changed.
119 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
120 // Size should have increased by 100,100.
121 EXPECT_EQ(gfx::Size(200, 200).ToString(), w1
->bounds().size().ToString());
124 TEST_F(ToplevelWindowEventHandlerTest
, GrowBox
) {
125 scoped_ptr
<aura::Window
> w1(CreateWindow(HTGROWBOX
));
126 TestWindowDelegate
* window_delegate
=
127 static_cast<TestWindowDelegate
*>(w1
->delegate());
128 window_delegate
->set_minimum_size(gfx::Size(40, 40));
130 gfx::Point position
= w1
->bounds().origin();
131 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
132 generator
.MoveMouseToCenterOf(w1
.get());
133 generator
.DragMouseBy(100, 100);
134 // Position should not have changed.
135 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
136 // Size should have increased by 100,100.
137 EXPECT_EQ(gfx::Size(200, 200).ToString(), w1
->bounds().size().ToString());
139 // Shrink the wnidow by (-100, -100).
140 generator
.DragMouseBy(-100, -100);
141 // Position should not have changed.
142 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
143 // Size should have decreased by 100,100.
144 EXPECT_EQ(gfx::Size(100, 100).ToString(), w1
->bounds().size().ToString());
146 // Enforce minimum size.
147 generator
.DragMouseBy(-60, -60);
148 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
149 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1
->bounds().size().ToString());
152 TEST_F(ToplevelWindowEventHandlerTest
, Right
) {
153 scoped_ptr
<aura::Window
> w1(CreateWindow(HTRIGHT
));
154 gfx::Point position
= w1
->bounds().origin();
155 DragFromCenterBy(w1
.get(), 100, 100);
156 // Position should not have changed.
157 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
158 // Size should have increased by 100,0.
159 EXPECT_EQ(gfx::Size(200, 100).ToString(), w1
->bounds().size().ToString());
162 TEST_F(ToplevelWindowEventHandlerTest
, Bottom
) {
163 scoped_ptr
<aura::Window
> w1(CreateWindow(HTBOTTOM
));
164 gfx::Point position
= w1
->bounds().origin();
165 DragFromCenterBy(w1
.get(), 100, 100);
166 // Position should not have changed.
167 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
168 // Size should have increased by 0,100.
169 EXPECT_EQ(gfx::Size(100, 200).ToString(), w1
->bounds().size().ToString());
172 TEST_F(ToplevelWindowEventHandlerTest
, TopRight
) {
173 scoped_ptr
<aura::Window
> w1(CreateWindow(HTTOPRIGHT
));
174 DragFromCenterBy(w1
.get(), -50, 50);
175 // Position should have been offset by 0,50.
176 EXPECT_EQ(gfx::Point(0, 50).ToString(), w1
->bounds().origin().ToString());
177 // Size should have decreased by 50,50.
178 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1
->bounds().size().ToString());
181 TEST_F(ToplevelWindowEventHandlerTest
, Top
) {
182 scoped_ptr
<aura::Window
> w1(CreateWindow(HTTOP
));
183 DragFromCenterBy(w1
.get(), 50, 50);
184 // Position should have been offset by 0,50.
185 EXPECT_EQ(gfx::Point(0, 50).ToString(), w1
->bounds().origin().ToString());
186 // Size should have decreased by 0,50.
187 EXPECT_EQ(gfx::Size(100, 50).ToString(), w1
->bounds().size().ToString());
190 TEST_F(ToplevelWindowEventHandlerTest
, Left
) {
191 scoped_ptr
<aura::Window
> w1(CreateWindow(HTLEFT
));
192 DragFromCenterBy(w1
.get(), 50, 50);
193 // Position should have been offset by 50,0.
194 EXPECT_EQ(gfx::Point(50, 0).ToString(), w1
->bounds().origin().ToString());
195 // Size should have decreased by 50,0.
196 EXPECT_EQ(gfx::Size(50, 100).ToString(), w1
->bounds().size().ToString());
199 TEST_F(ToplevelWindowEventHandlerTest
, BottomLeft
) {
200 scoped_ptr
<aura::Window
> w1(CreateWindow(HTBOTTOMLEFT
));
201 DragFromCenterBy(w1
.get(), 50, -50);
202 // Position should have been offset by 50,0.
203 EXPECT_EQ(gfx::Point(50, 0).ToString(), w1
->bounds().origin().ToString());
204 // Size should have decreased by 50,50.
205 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1
->bounds().size().ToString());
208 TEST_F(ToplevelWindowEventHandlerTest
, TopLeft
) {
209 scoped_ptr
<aura::Window
> w1(CreateWindow(HTTOPLEFT
));
210 DragFromCenterBy(w1
.get(), 50, 50);
211 // Position should have been offset by 50,50.
212 EXPECT_EQ(gfx::Point(50, 50).ToString(), w1
->bounds().origin().ToString());
213 // Size should have decreased by 50,50.
214 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1
->bounds().size().ToString());
217 TEST_F(ToplevelWindowEventHandlerTest
, Client
) {
218 scoped_ptr
<aura::Window
> w1(CreateWindow(HTCLIENT
));
219 gfx::Rect bounds
= w1
->bounds();
220 DragFromCenterBy(w1
.get(), 100, 100);
221 // Neither position nor size should have changed.
222 EXPECT_EQ(bounds
.ToString(), w1
->bounds().ToString());
225 TEST_F(ToplevelWindowEventHandlerTest
, LeftPastMinimum
) {
226 scoped_ptr
<aura::Window
> w1(CreateWindow(HTLEFT
));
227 TestWindowDelegate
* window_delegate
=
228 static_cast<TestWindowDelegate
*>(w1
->delegate());
229 window_delegate
->set_minimum_size(gfx::Size(40, 40));
231 // Simulate a large left-to-right drag. Window width should be clamped to
232 // minimum and position change should be limited as well.
233 DragFromCenterBy(w1
.get(), 333, 0);
234 EXPECT_EQ(gfx::Point(60, 0).ToString(), w1
->bounds().origin().ToString());
235 EXPECT_EQ(gfx::Size(40, 100).ToString(), w1
->bounds().size().ToString());
238 TEST_F(ToplevelWindowEventHandlerTest
, RightPastMinimum
) {
239 scoped_ptr
<aura::Window
> w1(CreateWindow(HTRIGHT
));
240 TestWindowDelegate
* window_delegate
=
241 static_cast<TestWindowDelegate
*>(w1
->delegate());
242 window_delegate
->set_minimum_size(gfx::Size(40, 40));
243 gfx::Point position
= w1
->bounds().origin();
245 // Simulate a large right-to-left drag. Window width should be clamped to
246 // minimum and position should not change.
247 DragFromCenterBy(w1
.get(), -333, 0);
248 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
249 EXPECT_EQ(gfx::Size(40, 100).ToString(), w1
->bounds().size().ToString());
252 TEST_F(ToplevelWindowEventHandlerTest
, TopLeftPastMinimum
) {
253 scoped_ptr
<aura::Window
> w1(CreateWindow(HTTOPLEFT
));
254 TestWindowDelegate
* window_delegate
=
255 static_cast<TestWindowDelegate
*>(w1
->delegate());
256 window_delegate
->set_minimum_size(gfx::Size(40, 40));
258 // Simulate a large top-left to bottom-right drag. Window width should be
259 // clamped to minimum and position should be limited.
260 DragFromCenterBy(w1
.get(), 333, 444);
261 EXPECT_EQ(gfx::Point(60, 60).ToString(), w1
->bounds().origin().ToString());
262 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1
->bounds().size().ToString());
265 TEST_F(ToplevelWindowEventHandlerTest
, TopRightPastMinimum
) {
266 scoped_ptr
<aura::Window
> w1(CreateWindow(HTTOPRIGHT
));
267 TestWindowDelegate
* window_delegate
=
268 static_cast<TestWindowDelegate
*>(w1
->delegate());
269 window_delegate
->set_minimum_size(gfx::Size(40, 40));
271 // Simulate a large top-right to bottom-left drag. Window size should be
272 // clamped to minimum, x position should not change, and y position should
274 DragFromCenterBy(w1
.get(), -333, 444);
275 EXPECT_EQ(gfx::Point(0, 60).ToString(), w1
->bounds().origin().ToString());
276 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1
->bounds().size().ToString());
279 TEST_F(ToplevelWindowEventHandlerTest
, BottomLeftPastMinimum
) {
280 scoped_ptr
<aura::Window
> w1(CreateWindow(HTBOTTOMLEFT
));
281 TestWindowDelegate
* window_delegate
=
282 static_cast<TestWindowDelegate
*>(w1
->delegate());
283 window_delegate
->set_minimum_size(gfx::Size(40, 40));
285 // Simulate a large bottom-left to top-right drag. Window size should be
286 // clamped to minimum, x position should be clamped, and y position should
288 DragFromCenterBy(w1
.get(), 333, -444);
289 EXPECT_EQ(gfx::Point(60, 0).ToString(), w1
->bounds().origin().ToString());
290 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1
->bounds().size().ToString());
293 TEST_F(ToplevelWindowEventHandlerTest
, BottomRightPastMinimum
) {
294 scoped_ptr
<aura::Window
> w1(CreateWindow(HTBOTTOMRIGHT
));
295 TestWindowDelegate
* window_delegate
=
296 static_cast<TestWindowDelegate
*>(w1
->delegate());
297 window_delegate
->set_minimum_size(gfx::Size(40, 40));
298 gfx::Point position
= w1
->bounds().origin();
300 // Simulate a large bottom-right to top-left drag. Window size should be
301 // clamped to minimum and position should not change.
302 DragFromCenterBy(w1
.get(), -333, -444);
303 EXPECT_EQ(position
.ToString(), w1
->bounds().origin().ToString());
304 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1
->bounds().size().ToString());
307 TEST_F(ToplevelWindowEventHandlerTest
, BottomRightWorkArea
) {
308 scoped_ptr
<aura::Window
> target(CreateWindow(HTBOTTOMRIGHT
));
309 gfx::Rect work_area
= Shell::GetScreen()->GetDisplayNearestWindow(
310 target
.get()).work_area();
311 gfx::Point position
= target
->bounds().origin();
312 // Drag further than work_area bottom.
313 DragFromCenterBy(target
.get(), 100, work_area
.height());
314 // Position should not have changed.
315 EXPECT_EQ(position
.ToString(), target
->bounds().origin().ToString());
316 // Size should have increased by 100, work_area.height() - target->bounds.y()
318 gfx::Size(200, work_area
.height() - target
->bounds().y()).ToString(),
319 target
->bounds().size().ToString());
322 TEST_F(ToplevelWindowEventHandlerTest
, BottomLeftWorkArea
) {
323 scoped_ptr
<aura::Window
> target(CreateWindow(HTBOTTOMLEFT
));
324 gfx::Rect work_area
= Shell::GetScreen()->GetDisplayNearestWindow(
325 target
.get()).work_area();
326 gfx::Point position
= target
->bounds().origin();
327 // Drag further than work_area bottom.
328 DragFromCenterBy(target
.get(), -30, work_area
.height());
329 // origin is now at 70, 100.
330 EXPECT_EQ(position
.x() - 30, target
->bounds().x());
331 EXPECT_EQ(position
.y(), target
->bounds().y());
332 // Size should have increased by 30, work_area.height() - target->bounds.y()
334 gfx::Size(130, work_area
.height() - target
->bounds().y()).ToString(),
335 target
->bounds().size().ToString());
338 TEST_F(ToplevelWindowEventHandlerTest
, BottomWorkArea
) {
339 scoped_ptr
<aura::Window
> target(CreateWindow(HTBOTTOM
));
340 gfx::Rect work_area
= Shell::GetScreen()->GetDisplayNearestWindow(
341 target
.get()).work_area();
342 gfx::Point position
= target
->bounds().origin();
343 // Drag further than work_area bottom.
344 DragFromCenterBy(target
.get(), 0, work_area
.height());
345 // Position should not have changed.
346 EXPECT_EQ(position
.ToString(), target
->bounds().origin().ToString());
347 // Size should have increased by 0, work_area.height() - target->bounds.y()
349 gfx::Size(100, work_area
.height() - target
->bounds().y()).ToString(),
350 target
->bounds().size().ToString());
353 TEST_F(ToplevelWindowEventHandlerTest
, DontDragIfModalChild
) {
354 scoped_ptr
<aura::Window
> w1(CreateWindow(HTCAPTION
));
355 scoped_ptr
<aura::Window
> w2(CreateWindow(HTCAPTION
));
356 w2
->SetBounds(gfx::Rect(100, 0, 100, 100));
357 w2
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_WINDOW
);
358 ::wm::AddTransientChild(w1
.get(), w2
.get());
359 gfx::Size size
= w1
->bounds().size();
361 // Attempt to drag w1, position and size should not change because w1 has a
363 DragFromCenterBy(w1
.get(), 100, 100);
364 EXPECT_EQ("0,0", w1
->bounds().origin().ToString());
365 EXPECT_EQ(size
.ToString(), w1
->bounds().size().ToString());
367 TouchDragFromCenterBy(w1
.get(), 100, 100);
368 EXPECT_EQ("0,0", w1
->bounds().origin().ToString());
369 EXPECT_EQ(size
.ToString(), w1
->bounds().size().ToString());
372 // Verifies we don't let windows drag to a -y location.
373 TEST_F(ToplevelWindowEventHandlerTest
, DontDragToNegativeY
) {
374 scoped_ptr
<aura::Window
> target(CreateWindow(HTTOP
));
375 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
377 generator
.MoveMouseTo(0, 5);
378 generator
.DragMouseBy(0, -5);
379 // The y location and height should not have changed.
380 EXPECT_EQ(0, target
->bounds().y());
381 EXPECT_EQ(100, target
->bounds().height());
384 // Verifies we don't let windows go bigger than the display width.
385 TEST_F(ToplevelWindowEventHandlerTest
, DontGotWiderThanScreen
) {
386 scoped_ptr
<aura::Window
> target(CreateWindow(HTRIGHT
));
387 gfx::Rect work_area
= Shell::GetScreen()->GetDisplayNearestWindow(
388 target
.get()).bounds();
389 DragFromCenterBy(target
.get(), work_area
.width() * 2, 0);
390 // The y location and height should not have changed.
391 EXPECT_EQ(work_area
.width(), target
->bounds().width());
394 // Verifies that touch-gestures drag the window correctly.
395 TEST_F(ToplevelWindowEventHandlerTest
, GestureDrag
) {
396 scoped_ptr
<aura::Window
> target(
397 CreateTestWindowInShellWithDelegate(
398 new TestWindowDelegate(HTCAPTION
),
400 gfx::Rect(0, 0, 100, 100)));
401 wm::WindowState
* window_state
= wm::GetWindowState(target
.get());
402 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
404 gfx::Rect old_bounds
= target
->bounds();
405 gfx::Point
location(5, 5);
406 target
->SetProperty(aura::client::kCanMaximizeKey
, true);
408 gfx::Point end
= location
;
412 generator
.GestureScrollSequence(location
, end
,
413 base::TimeDelta::FromMilliseconds(5),
415 RunAllPendingInMessageLoop();
417 // Verify that the window has moved after the gesture.
418 EXPECT_NE(old_bounds
.ToString(), target
->bounds().ToString());
419 EXPECT_EQ(wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED
, window_state
->GetStateType());
421 old_bounds
= target
->bounds();
424 end
= location
= target
->GetBoundsInRootWindow().CenterPoint();
426 generator
.GestureScrollSequence(location
, end
,
427 base::TimeDelta::FromMilliseconds(5),
429 RunAllPendingInMessageLoop();
431 EXPECT_NE(old_bounds
.ToString(), target
->bounds().ToString());
432 EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED
, window_state
->GetStateType());
434 gfx::Rect bounds_before_maximization
= target
->bounds();
435 bounds_before_maximization
.Offset(0, 100);
436 target
->SetBounds(bounds_before_maximization
);
437 old_bounds
= target
->bounds();
440 end
= location
= target
->GetBoundsInRootWindow().CenterPoint();
442 generator
.GestureScrollSequence(location
, end
,
443 base::TimeDelta::FromMilliseconds(5),
445 RunAllPendingInMessageLoop();
447 EXPECT_NE(old_bounds
.ToString(), target
->bounds().ToString());
448 EXPECT_TRUE(window_state
->IsMaximized());
449 EXPECT_EQ(old_bounds
.ToString(),
450 window_state
->GetRestoreBoundsInScreen().ToString());
452 window_state
->Restore();
453 target
->SetBounds(old_bounds
);
456 end
= location
= target
->GetBoundsInRootWindow().CenterPoint();
458 generator
.GestureScrollSequence(location
, end
,
459 base::TimeDelta::FromMilliseconds(5),
461 RunAllPendingInMessageLoop();
462 EXPECT_NE(old_bounds
.ToString(), target
->bounds().ToString());
463 EXPECT_TRUE(window_state
->IsMinimized());
464 EXPECT_TRUE(window_state
->unminimize_to_restore_bounds());
465 EXPECT_EQ(old_bounds
.ToString(),
466 window_state
->GetRestoreBoundsInScreen().ToString());
469 // Tests that a gesture cannot minimize an unminimizeable window.
470 TEST_F(ToplevelWindowEventHandlerTest
,
471 GestureAttemptMinimizeUnminimizeableWindow
) {
472 scoped_ptr
<aura::Window
> target(CreateWindow(HTCAPTION
));
473 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
475 gfx::Rect old_bounds
= target
->bounds();
476 gfx::Point
location(5, 5);
477 target
->SetProperty(aura::client::kCanMaximizeKey
, true);
478 target
->SetProperty(aura::client::kCanMinimizeKey
, false);
480 gfx::Point end
= location
;
482 generator
.GestureScrollSequence(location
, end
,
483 base::TimeDelta::FromMilliseconds(5),
485 RunAllPendingInMessageLoop();
486 EXPECT_FALSE(wm::GetWindowState(target
.get())->IsMinimized());
489 TEST_F(ToplevelWindowEventHandlerTest
, GestureDragToRestore
) {
490 scoped_ptr
<aura::Window
> window(
491 CreateTestWindowInShellWithDelegate(
492 new TestWindowDelegate(HTCAPTION
),
494 gfx::Rect(10, 20, 30, 40)));
496 wm::WindowState
* window_state
= wm::GetWindowState(window
.get());
497 window_state
->Activate();
499 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
501 gfx::Rect old_bounds
= window
->bounds();
502 gfx::Point location
, end
;
503 end
= location
= window
->GetBoundsInRootWindow().CenterPoint();
505 generator
.GestureScrollSequence(location
, end
,
506 base::TimeDelta::FromMilliseconds(5),
508 RunAllPendingInMessageLoop();
509 EXPECT_NE(old_bounds
.ToString(), window
->bounds().ToString());
510 EXPECT_TRUE(window_state
->IsMinimized());
511 EXPECT_TRUE(window_state
->unminimize_to_restore_bounds());
512 EXPECT_EQ(old_bounds
.ToString(),
513 window_state
->GetRestoreBoundsInScreen().ToString());
516 // Tests that an unresizable window cannot be dragged or snapped using gestures.
517 TEST_F(ToplevelWindowEventHandlerTest
, GestureDragForUnresizableWindow
) {
518 scoped_ptr
<aura::Window
> target(CreateWindow(HTCAPTION
));
519 wm::WindowState
* window_state
= wm::GetWindowState(target
.get());
521 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
523 gfx::Rect old_bounds
= target
->bounds();
524 gfx::Point
location(5, 5);
526 target
->SetProperty(aura::client::kCanResizeKey
, false);
528 gfx::Point end
= location
;
530 // Try to snap right. The window is not resizable. So it should not snap.
532 generator
.GestureScrollSequence(location
, end
,
533 base::TimeDelta::FromMilliseconds(5),
535 RunAllPendingInMessageLoop();
537 // Verify that the window has moved after the gesture.
538 gfx::Rect
expected_bounds(old_bounds
);
539 expected_bounds
.Offset(gfx::Vector2d(100, 0));
540 EXPECT_EQ(expected_bounds
.ToString(), target
->bounds().ToString());
542 // Verify that the window did not snap left.
543 EXPECT_TRUE(window_state
->IsNormalStateType());
545 old_bounds
= target
->bounds();
547 // Try to snap left. It should not snap.
548 end
= location
= target
->GetBoundsInRootWindow().CenterPoint();
550 generator
.GestureScrollSequence(location
, end
,
551 base::TimeDelta::FromMilliseconds(5),
553 RunAllPendingInMessageLoop();
555 // Verify that the window has moved after the gesture.
556 expected_bounds
= old_bounds
;
557 expected_bounds
.Offset(gfx::Vector2d(-100, 0));
558 EXPECT_EQ(expected_bounds
.ToString(), target
->bounds().ToString());
560 // Verify that the window did not snap left.
561 EXPECT_TRUE(window_state
->IsNormalStateType());
564 // Tests that dragging multiple windows at the same time is not allowed.
565 TEST_F(ToplevelWindowEventHandlerTest
, GestureDragMultipleWindows
) {
566 scoped_ptr
<aura::Window
> target(
567 CreateTestWindowInShellWithDelegate(
568 new TestWindowDelegate(HTCAPTION
),
570 gfx::Rect(0, 0, 100, 100)));
571 scoped_ptr
<aura::Window
> notmoved(
572 CreateTestWindowInShellWithDelegate(
573 new TestWindowDelegate(HTCAPTION
),
574 1, gfx::Rect(100, 0, 100, 100)));
576 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
578 gfx::Rect old_bounds
= target
->bounds();
579 gfx::Point
location(5, 5);
580 target
->SetProperty(aura::client::kCanMaximizeKey
, true);
582 // Send some touch events to start dragging |target|.
583 generator
.MoveTouch(location
);
584 generator
.PressTouch();
585 location
.Offset(40, 5);
586 generator
.MoveTouch(location
);
588 // Try to drag |notmoved| window. This should not move the window.
590 gfx::Rect bounds
= notmoved
->bounds();
591 ui::test::EventGenerator
gen(Shell::GetPrimaryRootWindow(), notmoved
.get());
592 gfx::Point start
= notmoved
->bounds().origin() + gfx::Vector2d(10, 10);
593 gfx::Point end
= start
+ gfx::Vector2d(100, 10);
594 gen
.GestureScrollSequence(start
, end
,
595 base::TimeDelta::FromMilliseconds(10),
597 EXPECT_EQ(bounds
.ToString(), notmoved
->bounds().ToString());
601 // Verifies pressing escape resets the bounds to the original bounds.
602 // Disabled crbug.com/166219.
604 #define MAYBE_EscapeReverts DISABLED_EscapeReverts
606 #define MAYBE_EscapeReverts EscapeReverts
608 TEST_F(ToplevelWindowEventHandlerTest
, MAYBE_EscapeReverts
) {
609 scoped_ptr
<aura::Window
> target(CreateWindow(HTBOTTOMRIGHT
));
610 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
612 generator
.PressLeftButton();
613 generator
.MoveMouseBy(10, 11);
615 // Execute any scheduled draws so that pending mouse events are processed.
616 RunAllPendingInMessageLoop();
618 EXPECT_EQ("0,0 110x111", target
->bounds().ToString());
619 generator
.PressKey(ui::VKEY_ESCAPE
, 0);
620 generator
.ReleaseKey(ui::VKEY_ESCAPE
, 0);
621 EXPECT_EQ("0,0 100x100", target
->bounds().ToString());
624 // Verifies window minimization/maximization completes drag.
625 // Disabled crbug.com/166219.
627 #define MAYBE_MinimizeMaximizeCompletes DISABLED_MinimizeMaximizeCompletes
629 #define MAYBE_MinimizeMaximizeCompletes MinimizeMaximizeCompletes
631 TEST_F(ToplevelWindowEventHandlerTest
, MAYBE_MinimizeMaximizeCompletes
) {
632 // Once window is minimized, window dragging completes.
634 scoped_ptr
<aura::Window
> target(CreateWindow(HTCAPTION
));
636 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
638 generator
.PressLeftButton();
639 generator
.MoveMouseBy(10, 11);
640 RunAllPendingInMessageLoop();
641 EXPECT_EQ("10,11 100x100", target
->bounds().ToString());
642 wm::WindowState
* window_state
= wm::GetWindowState(target
.get());
643 window_state
->Minimize();
644 window_state
->Restore();
646 generator
.PressLeftButton();
647 generator
.MoveMouseBy(10, 11);
648 RunAllPendingInMessageLoop();
649 EXPECT_EQ("10,11 100x100", target
->bounds().ToString());
652 // Once window is maximized, window dragging completes.
654 scoped_ptr
<aura::Window
> target(CreateWindow(HTCAPTION
));
656 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
658 generator
.PressLeftButton();
659 generator
.MoveMouseBy(10, 11);
660 RunAllPendingInMessageLoop();
661 EXPECT_EQ("10,11 100x100", target
->bounds().ToString());
662 wm::WindowState
* window_state
= wm::GetWindowState(target
.get());
663 window_state
->Maximize();
664 window_state
->Restore();
666 generator
.PressLeftButton();
667 generator
.MoveMouseBy(10, 11);
668 RunAllPendingInMessageLoop();
669 EXPECT_EQ("10,11 100x100", target
->bounds().ToString());
673 // Verifies that a drag cannot be started via
674 // aura::client::WindowMoveClient::RunMoveLoop() while another drag is already
676 TEST_F(ToplevelWindowEventHandlerTest
, RunMoveLoopFailsDuringInProgressDrag
) {
677 scoped_ptr
<aura::Window
> window1(CreateWindow(HTCAPTION
));
678 EXPECT_EQ("0,0 100x100", window1
->bounds().ToString());
679 scoped_ptr
<aura::Window
> window2(CreateWindow(HTCAPTION
));
681 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
684 generator
.PressLeftButton();
685 generator
.MoveMouseBy(10, 11);
686 EXPECT_EQ("10,11 100x100", window1
->bounds().ToString());
688 aura::client::WindowMoveClient
* move_client
=
689 aura::client::GetWindowMoveClient(window2
->GetRootWindow());
690 EXPECT_EQ(aura::client::MOVE_CANCELED
,
691 move_client
->RunMoveLoop(window2
.get(), gfx::Vector2d(),
692 aura::client::WINDOW_MOVE_SOURCE_MOUSE
));
694 generator
.ReleaseLeftButton();
695 EXPECT_EQ("10,11 100x100", window1
->bounds().ToString());
700 void SendMouseReleaseAndReleaseCapture(ui::test::EventGenerator
* generator
,
701 aura::Window
* window
) {
702 generator
->ReleaseLeftButton();
703 window
->ReleaseCapture();
708 // Test that a drag is successful even if ET_MOUSE_CAPTURE_CHANGED is sent
709 // immediately after the mouse release. views::Widget has this behavior.
710 TEST_F(ToplevelWindowEventHandlerTest
, CaptureLossAfterMouseRelease
) {
711 scoped_ptr
<aura::Window
> window(CreateWindow(HTNOWHERE
));
712 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
714 generator
.PressLeftButton();
715 window
->SetCapture();
717 aura::client::WindowMoveClient
* move_client
=
718 aura::client::GetWindowMoveClient(window
->GetRootWindow());
719 base::MessageLoopForUI::current()->PostTask(
721 base::Bind(&SendMouseReleaseAndReleaseCapture
,
722 base::Unretained(&generator
),
723 base::Unretained(window
.get())));
724 EXPECT_EQ(aura::client::MOVE_SUCCESSFUL
,
725 move_client
->RunMoveLoop(window
.get(), gfx::Vector2d(),
726 aura::client::WINDOW_MOVE_SOURCE_MOUSE
));
731 // Checks that |window| has capture and releases capture.
732 void CheckHasCaptureAndReleaseCapture(aura::Window
* window
) {
733 ASSERT_TRUE(window
->HasCapture());
734 window
->ReleaseCapture();
739 // Test that releasing capture cancels an in-progress gesture drag.
740 TEST_F(ToplevelWindowEventHandlerTest
, GestureDragCaptureLoss
) {
741 scoped_ptr
<aura::Window
> window(CreateWindow(HTNOWHERE
));
742 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
745 aura::client::WindowMoveClient
* move_client
=
746 aura::client::GetWindowMoveClient(window
->GetRootWindow());
747 base::ThreadTaskRunnerHandle::Get()->PostTask(
748 FROM_HERE
, base::Bind(&CheckHasCaptureAndReleaseCapture
,
749 base::Unretained(window
.get())));
750 EXPECT_EQ(aura::client::MOVE_CANCELED
,
751 move_client
->RunMoveLoop(window
.get(), gfx::Vector2d(),
752 aura::client::WINDOW_MOVE_SOURCE_TOUCH
));
755 // Showing the resize shadows when the mouse is over the window edges is tested
756 // in resize_shadow_and_cursor_test.cc