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/lock_state_controller.h"
12 #include "ash/wm/resize_shadow.h"
13 #include "ash/wm/resize_shadow_controller.h"
14 #include "ash/wm/window_state.h"
15 #include "ash/wm/window_util.h"
16 #include "ash/wm/workspace/snap_sizer.h"
17 #include "ash/wm/workspace_controller.h"
18 #include "base/basictypes.h"
19 #include "base/compiler_specific.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "ui/aura/client/aura_constants.h"
22 #include "ui/aura/client/window_move_client.h"
23 #include "ui/aura/root_window.h"
24 #include "ui/aura/test/aura_test_base.h"
25 #include "ui/aura/test/event_generator.h"
26 #include "ui/aura/test/test_window_delegate.h"
27 #include "ui/base/hit_test.h"
28 #include "ui/events/event.h"
29 #include "ui/gfx/screen.h"
30 #include "ui/views/corewm/window_util.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 virtual ~TestWindowDelegate() {}
54 // Overridden from aura::Test::TestWindowDelegate:
55 virtual void OnWindowDestroyed() OVERRIDE {
59 DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
62 class ToplevelWindowEventHandlerTest : public AshTestBase {
64 ToplevelWindowEventHandlerTest() {}
65 virtual ~ToplevelWindowEventHandlerTest() {}
68 aura::Window* CreateWindow(int hittest_code) {
69 TestWindowDelegate* d1 = new TestWindowDelegate(hittest_code);
70 aura::Window* w1 = new aura::Window(d1);
71 w1->SetType(ui::wm::WINDOW_TYPE_NORMAL);
73 w1->Init(aura::WINDOW_LAYER_TEXTURED);
74 aura::Window* parent =
75 Shell::GetContainer(Shell::GetPrimaryRootWindow(),
76 internal::kShellWindowId_AlwaysOnTopContainer);
78 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
83 void DragFromCenterBy(aura::Window* window, int dx, int dy) {
84 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), window);
85 generator.DragMouseBy(dx, dy);
88 void TouchDragFromCenterBy(aura::Window* window, int dx, int dy) {
89 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), window);
90 generator.PressMoveAndReleaseTouchBy(dx, dy);
93 scoped_ptr<ToplevelWindowEventHandler> handler_;
96 DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventHandlerTest);
101 TEST_F(ToplevelWindowEventHandlerTest, Caption) {
102 scoped_ptr<aura::Window> w1(CreateWindow(HTCAPTION));
103 gfx::Size size = w1->bounds().size();
104 DragFromCenterBy(w1.get(), 100, 100);
105 // Position should have been offset by 100,100.
106 EXPECT_EQ("100,100", w1->bounds().origin().ToString());
107 // Size should not have.
108 EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
110 TouchDragFromCenterBy(w1.get(), 100, 100);
111 // Position should have been offset by 100,100.
112 EXPECT_EQ("200,200", w1->bounds().origin().ToString());
113 // Size should not have.
114 EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
117 TEST_F(ToplevelWindowEventHandlerTest, BottomRight) {
118 scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMRIGHT));
119 gfx::Point position = w1->bounds().origin();
120 DragFromCenterBy(w1.get(), 100, 100);
121 // Position should not have changed.
122 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
123 // Size should have increased by 100,100.
124 EXPECT_EQ(gfx::Size(200, 200).ToString(), w1->bounds().size().ToString());
127 TEST_F(ToplevelWindowEventHandlerTest, GrowBox) {
128 scoped_ptr<aura::Window> w1(CreateWindow(HTGROWBOX));
129 TestWindowDelegate* window_delegate =
130 static_cast<TestWindowDelegate*>(w1->delegate());
131 window_delegate->set_minimum_size(gfx::Size(40, 40));
133 gfx::Point position = w1->bounds().origin();
134 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
135 generator.MoveMouseToCenterOf(w1.get());
136 generator.DragMouseBy(100, 100);
137 // Position should not have changed.
138 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
139 // Size should have increased by 100,100.
140 EXPECT_EQ(gfx::Size(200, 200).ToString(), w1->bounds().size().ToString());
142 // Shrink the wnidow by (-100, -100).
143 generator.DragMouseBy(-100, -100);
144 // Position should not have changed.
145 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
146 // Size should have decreased by 100,100.
147 EXPECT_EQ(gfx::Size(100, 100).ToString(), w1->bounds().size().ToString());
149 // Enforce minimum size.
150 generator.DragMouseBy(-60, -60);
151 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
152 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
155 TEST_F(ToplevelWindowEventHandlerTest, Right) {
156 scoped_ptr<aura::Window> w1(CreateWindow(HTRIGHT));
157 gfx::Point position = w1->bounds().origin();
158 DragFromCenterBy(w1.get(), 100, 100);
159 // Position should not have changed.
160 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
161 // Size should have increased by 100,0.
162 EXPECT_EQ(gfx::Size(200, 100).ToString(), w1->bounds().size().ToString());
165 TEST_F(ToplevelWindowEventHandlerTest, Bottom) {
166 scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOM));
167 gfx::Point position = w1->bounds().origin();
168 DragFromCenterBy(w1.get(), 100, 100);
169 // Position should not have changed.
170 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
171 // Size should have increased by 0,100.
172 EXPECT_EQ(gfx::Size(100, 200).ToString(), w1->bounds().size().ToString());
175 TEST_F(ToplevelWindowEventHandlerTest, TopRight) {
176 scoped_ptr<aura::Window> w1(CreateWindow(HTTOPRIGHT));
177 DragFromCenterBy(w1.get(), -50, 50);
178 // Position should have been offset by 0,50.
179 EXPECT_EQ(gfx::Point(0, 50).ToString(), w1->bounds().origin().ToString());
180 // Size should have decreased by 50,50.
181 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
184 TEST_F(ToplevelWindowEventHandlerTest, Top) {
185 scoped_ptr<aura::Window> w1(CreateWindow(HTTOP));
186 DragFromCenterBy(w1.get(), 50, 50);
187 // Position should have been offset by 0,50.
188 EXPECT_EQ(gfx::Point(0, 50).ToString(), w1->bounds().origin().ToString());
189 // Size should have decreased by 0,50.
190 EXPECT_EQ(gfx::Size(100, 50).ToString(), w1->bounds().size().ToString());
193 TEST_F(ToplevelWindowEventHandlerTest, Left) {
194 scoped_ptr<aura::Window> w1(CreateWindow(HTLEFT));
195 DragFromCenterBy(w1.get(), 50, 50);
196 // Position should have been offset by 50,0.
197 EXPECT_EQ(gfx::Point(50, 0).ToString(), w1->bounds().origin().ToString());
198 // Size should have decreased by 50,0.
199 EXPECT_EQ(gfx::Size(50, 100).ToString(), w1->bounds().size().ToString());
202 TEST_F(ToplevelWindowEventHandlerTest, BottomLeft) {
203 scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMLEFT));
204 DragFromCenterBy(w1.get(), 50, -50);
205 // Position should have been offset by 50,0.
206 EXPECT_EQ(gfx::Point(50, 0).ToString(), w1->bounds().origin().ToString());
207 // Size should have decreased by 50,50.
208 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
211 TEST_F(ToplevelWindowEventHandlerTest, TopLeft) {
212 scoped_ptr<aura::Window> w1(CreateWindow(HTTOPLEFT));
213 DragFromCenterBy(w1.get(), 50, 50);
214 // Position should have been offset by 50,50.
215 EXPECT_EQ(gfx::Point(50, 50).ToString(), w1->bounds().origin().ToString());
216 // Size should have decreased by 50,50.
217 EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
220 TEST_F(ToplevelWindowEventHandlerTest, Client) {
221 scoped_ptr<aura::Window> w1(CreateWindow(HTCLIENT));
222 gfx::Rect bounds = w1->bounds();
223 DragFromCenterBy(w1.get(), 100, 100);
224 // Neither position nor size should have changed.
225 EXPECT_EQ(bounds.ToString(), w1->bounds().ToString());
228 TEST_F(ToplevelWindowEventHandlerTest, LeftPastMinimum) {
229 scoped_ptr<aura::Window> w1(CreateWindow(HTLEFT));
230 TestWindowDelegate* window_delegate =
231 static_cast<TestWindowDelegate*>(w1->delegate());
232 window_delegate->set_minimum_size(gfx::Size(40, 40));
234 // Simulate a large left-to-right drag. Window width should be clamped to
235 // minimum and position change should be limited as well.
236 DragFromCenterBy(w1.get(), 333, 0);
237 EXPECT_EQ(gfx::Point(60, 0).ToString(), w1->bounds().origin().ToString());
238 EXPECT_EQ(gfx::Size(40, 100).ToString(), w1->bounds().size().ToString());
241 TEST_F(ToplevelWindowEventHandlerTest, RightPastMinimum) {
242 scoped_ptr<aura::Window> w1(CreateWindow(HTRIGHT));
243 TestWindowDelegate* window_delegate =
244 static_cast<TestWindowDelegate*>(w1->delegate());
245 window_delegate->set_minimum_size(gfx::Size(40, 40));
246 gfx::Point position = w1->bounds().origin();
248 // Simulate a large right-to-left drag. Window width should be clamped to
249 // minimum and position should not change.
250 DragFromCenterBy(w1.get(), -333, 0);
251 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
252 EXPECT_EQ(gfx::Size(40, 100).ToString(), w1->bounds().size().ToString());
255 TEST_F(ToplevelWindowEventHandlerTest, TopLeftPastMinimum) {
256 scoped_ptr<aura::Window> w1(CreateWindow(HTTOPLEFT));
257 TestWindowDelegate* window_delegate =
258 static_cast<TestWindowDelegate*>(w1->delegate());
259 window_delegate->set_minimum_size(gfx::Size(40, 40));
261 // Simulate a large top-left to bottom-right drag. Window width should be
262 // clamped to minimum and position should be limited.
263 DragFromCenterBy(w1.get(), 333, 444);
264 EXPECT_EQ(gfx::Point(60, 60).ToString(), w1->bounds().origin().ToString());
265 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
268 TEST_F(ToplevelWindowEventHandlerTest, TopRightPastMinimum) {
269 scoped_ptr<aura::Window> w1(CreateWindow(HTTOPRIGHT));
270 TestWindowDelegate* window_delegate =
271 static_cast<TestWindowDelegate*>(w1->delegate());
272 window_delegate->set_minimum_size(gfx::Size(40, 40));
274 // Simulate a large top-right to bottom-left drag. Window size should be
275 // clamped to minimum, x position should not change, and y position should
277 DragFromCenterBy(w1.get(), -333, 444);
278 EXPECT_EQ(gfx::Point(0, 60).ToString(), w1->bounds().origin().ToString());
279 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
282 TEST_F(ToplevelWindowEventHandlerTest, BottomLeftPastMinimum) {
283 scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMLEFT));
284 TestWindowDelegate* window_delegate =
285 static_cast<TestWindowDelegate*>(w1->delegate());
286 window_delegate->set_minimum_size(gfx::Size(40, 40));
288 // Simulate a large bottom-left to top-right drag. Window size should be
289 // clamped to minimum, x position should be clamped, and y position should
291 DragFromCenterBy(w1.get(), 333, -444);
292 EXPECT_EQ(gfx::Point(60, 0).ToString(), w1->bounds().origin().ToString());
293 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
296 TEST_F(ToplevelWindowEventHandlerTest, BottomRightPastMinimum) {
297 scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMRIGHT));
298 TestWindowDelegate* window_delegate =
299 static_cast<TestWindowDelegate*>(w1->delegate());
300 window_delegate->set_minimum_size(gfx::Size(40, 40));
301 gfx::Point position = w1->bounds().origin();
303 // Simulate a large bottom-right to top-left drag. Window size should be
304 // clamped to minimum and position should not change.
305 DragFromCenterBy(w1.get(), -333, -444);
306 EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
307 EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
310 TEST_F(ToplevelWindowEventHandlerTest, BottomRightWorkArea) {
311 scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT));
312 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
313 target.get()).work_area();
314 gfx::Point position = target->bounds().origin();
315 // Drag further than work_area bottom.
316 DragFromCenterBy(target.get(), 100, work_area.height());
317 // Position should not have changed.
318 EXPECT_EQ(position.ToString(), target->bounds().origin().ToString());
319 // Size should have increased by 100, work_area.height() - target->bounds.y()
321 gfx::Size(200, work_area.height() - target->bounds().y()).ToString(),
322 target->bounds().size().ToString());
325 TEST_F(ToplevelWindowEventHandlerTest, BottomLeftWorkArea) {
326 scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMLEFT));
327 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
328 target.get()).work_area();
329 gfx::Point position = target->bounds().origin();
330 // Drag further than work_area bottom.
331 DragFromCenterBy(target.get(), -30, work_area.height());
332 // origin is now at 70, 100.
333 EXPECT_EQ(position.x() - 30, target->bounds().x());
334 EXPECT_EQ(position.y(), target->bounds().y());
335 // Size should have increased by 30, work_area.height() - target->bounds.y()
337 gfx::Size(130, work_area.height() - target->bounds().y()).ToString(),
338 target->bounds().size().ToString());
341 TEST_F(ToplevelWindowEventHandlerTest, BottomWorkArea) {
342 scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOM));
343 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
344 target.get()).work_area();
345 gfx::Point position = target->bounds().origin();
346 // Drag further than work_area bottom.
347 DragFromCenterBy(target.get(), 0, work_area.height());
348 // Position should not have changed.
349 EXPECT_EQ(position.ToString(), target->bounds().origin().ToString());
350 // Size should have increased by 0, work_area.height() - target->bounds.y()
352 gfx::Size(100, work_area.height() - target->bounds().y()).ToString(),
353 target->bounds().size().ToString());
356 TEST_F(ToplevelWindowEventHandlerTest, DontDragIfModalChild) {
357 scoped_ptr<aura::Window> w1(CreateWindow(HTCAPTION));
358 scoped_ptr<aura::Window> w2(CreateWindow(HTCAPTION));
359 w2->SetBounds(gfx::Rect(100, 0, 100, 100));
360 w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
361 views::corewm::AddTransientChild(w1.get(), w2.get());
362 gfx::Size size = w1->bounds().size();
364 // Attempt to drag w1, position and size should not change because w1 has a
366 DragFromCenterBy(w1.get(), 100, 100);
367 EXPECT_EQ("0,0", w1->bounds().origin().ToString());
368 EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
370 TouchDragFromCenterBy(w1.get(), 100, 100);
371 EXPECT_EQ("0,0", w1->bounds().origin().ToString());
372 EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
375 // Verifies we don't let windows drag to a -y location.
376 TEST_F(ToplevelWindowEventHandlerTest, DontDragToNegativeY) {
377 scoped_ptr<aura::Window> target(CreateWindow(HTTOP));
378 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
380 generator.MoveMouseTo(0, 5);
381 generator.DragMouseBy(0, -5);
382 // The y location and height should not have changed.
383 EXPECT_EQ(0, target->bounds().y());
384 EXPECT_EQ(100, target->bounds().height());
387 // Verifies we don't let windows go bigger than the display width.
388 TEST_F(ToplevelWindowEventHandlerTest, DontGotWiderThanScreen) {
389 scoped_ptr<aura::Window> target(CreateWindow(HTRIGHT));
390 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
391 target.get()).bounds();
392 DragFromCenterBy(target.get(), work_area.width() * 2, 0);
393 // The y location and height should not have changed.
394 EXPECT_EQ(work_area.width(), target->bounds().width());
397 // Verifies that touch-gestures drag the window correctly.
398 TEST_F(ToplevelWindowEventHandlerTest, GestureDrag) {
399 scoped_ptr<aura::Window> target(
400 CreateTestWindowInShellWithDelegate(
401 new TestWindowDelegate(HTCAPTION),
403 gfx::Rect(0, 0, 100, 100)));
404 wm::WindowState* window_state = wm::GetWindowState(target.get());
405 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
407 gfx::Rect old_bounds = target->bounds();
408 gfx::Point location(5, 5);
409 target->SetProperty(aura::client::kCanMaximizeKey, true);
411 gfx::Point end = location;
415 // Get the expected snapped bounds before snapping.
416 internal::SnapSizer sizer(window_state, location,
417 internal::SnapSizer::RIGHT_EDGE,
418 internal::SnapSizer::OTHER_INPUT);
419 gfx::Rect snapped_bounds = sizer.GetSnapBounds(target->bounds());
422 generator.GestureScrollSequence(location, end,
423 base::TimeDelta::FromMilliseconds(5),
425 RunAllPendingInMessageLoop();
427 // Verify that the window has moved after the gesture.
428 EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
429 EXPECT_EQ(snapped_bounds.ToString(), target->bounds().ToString());
432 old_bounds = target->bounds();
436 // Get the expected snapped bounds before snapping.
437 internal::SnapSizer sizer(window_state, location,
438 internal::SnapSizer::LEFT_EDGE,
439 internal::SnapSizer::OTHER_INPUT);
440 gfx::Rect snapped_bounds = sizer.GetSnapBounds(target->bounds());
441 end = location = target->GetBoundsInRootWindow().CenterPoint();
443 generator.GestureScrollSequence(location, end,
444 base::TimeDelta::FromMilliseconds(5),
446 RunAllPendingInMessageLoop();
448 EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
449 EXPECT_EQ(snapped_bounds.ToString(), target->bounds().ToString());
452 gfx::Rect bounds_before_maximization = target->bounds();
453 bounds_before_maximization.Offset(0, 100);
454 target->SetBounds(bounds_before_maximization);
455 old_bounds = target->bounds();
458 end = location = target->GetBoundsInRootWindow().CenterPoint();
460 generator.GestureScrollSequence(location, end,
461 base::TimeDelta::FromMilliseconds(5),
463 RunAllPendingInMessageLoop();
465 EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
466 EXPECT_TRUE(window_state->IsMaximized());
467 EXPECT_EQ(old_bounds.ToString(),
468 window_state->GetRestoreBoundsInScreen().ToString());
470 window_state->Restore();
471 target->SetBounds(old_bounds);
474 end = location = target->GetBoundsInRootWindow().CenterPoint();
476 generator.GestureScrollSequence(location, end,
477 base::TimeDelta::FromMilliseconds(5),
479 RunAllPendingInMessageLoop();
480 EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
481 EXPECT_TRUE(window_state->IsMinimized());
482 EXPECT_TRUE(window_state->unminimize_to_restore_bounds());
483 EXPECT_EQ(old_bounds.ToString(),
484 window_state->GetRestoreBoundsInScreen().ToString());
487 // Tests that a gesture cannot minimize a window in login/lock screen.
488 TEST_F(ToplevelWindowEventHandlerTest, GestureDragMinimizeLoginScreen) {
489 LockStateController* state_controller =
490 Shell::GetInstance()->lock_state_controller();
491 state_controller->OnLoginStateChanged(user::LOGGED_IN_NONE);
492 state_controller->OnLockStateChanged(false);
493 SetUserLoggedIn(false);
495 scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
496 aura::Window* lock = internal::RootWindowController::ForWindow(target.get())->
497 GetContainer(internal::kShellWindowId_LockSystemModalContainer);
498 lock->AddChild(target.get());
499 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
501 gfx::Rect old_bounds = target->bounds();
502 gfx::Point location(5, 5);
503 target->SetProperty(aura::client::kCanMaximizeKey, true);
505 gfx::Point end = location;
507 generator.GestureScrollSequence(location, end,
508 base::TimeDelta::FromMilliseconds(5),
510 RunAllPendingInMessageLoop();
511 EXPECT_FALSE(wm::GetWindowState(target.get())->IsMinimized());
514 TEST_F(ToplevelWindowEventHandlerTest, GestureDragToRestore) {
515 scoped_ptr<aura::Window> window(
516 CreateTestWindowInShellWithDelegate(
517 new TestWindowDelegate(HTCAPTION),
519 gfx::Rect(10, 20, 30, 40)));
521 wm::WindowState* window_state = wm::GetWindowState(window.get());
522 window_state->Activate();
524 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
526 gfx::Rect old_bounds = window->bounds();
527 gfx::Point location, end;
528 end = location = window->GetBoundsInRootWindow().CenterPoint();
530 generator.GestureScrollSequence(location, end,
531 base::TimeDelta::FromMilliseconds(5),
533 RunAllPendingInMessageLoop();
534 EXPECT_NE(old_bounds.ToString(), window->bounds().ToString());
535 EXPECT_TRUE(window_state->IsMinimized());
536 EXPECT_TRUE(window_state->unminimize_to_restore_bounds());
537 EXPECT_EQ(old_bounds.ToString(),
538 window_state->GetRestoreBoundsInScreen().ToString());
541 // Tests that an unresizable window cannot be dragged or snapped using gestures.
542 TEST_F(ToplevelWindowEventHandlerTest, GestureDragForUnresizableWindow) {
543 scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
544 wm::WindowState* window_state = wm::GetWindowState(target.get());
546 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
548 gfx::Rect old_bounds = target->bounds();
549 gfx::Point location(5, 5);
551 target->SetProperty(aura::client::kCanResizeKey, false);
553 gfx::Point end = location;
555 // Try to snap right. The window is not resizable. So it should not snap.
557 // Get the expected snapped bounds before the gesture.
558 internal::SnapSizer sizer(window_state, location,
559 internal::SnapSizer::RIGHT_EDGE,
560 internal::SnapSizer::OTHER_INPUT);
561 gfx::Rect snapped_bounds = sizer.GetSnapBounds(target->bounds());
564 generator.GestureScrollSequence(location, end,
565 base::TimeDelta::FromMilliseconds(5),
567 RunAllPendingInMessageLoop();
569 // Verify that the window has moved after the gesture.
570 gfx::Rect expected_bounds(old_bounds);
571 expected_bounds.Offset(gfx::Vector2d(100, 0));
572 EXPECT_EQ(expected_bounds.ToString(), target->bounds().ToString());
574 // Verify that the window did not snap left.
575 EXPECT_NE(snapped_bounds.ToString(), target->bounds().ToString());
578 old_bounds = target->bounds();
580 // Try to snap left. It should not snap.
582 // Get the expected snapped bounds before the gesture.
583 internal::SnapSizer sizer(window_state, location,
584 internal::SnapSizer::LEFT_EDGE,
585 internal::SnapSizer::OTHER_INPUT);
586 gfx::Rect snapped_bounds = sizer.GetSnapBounds(target->bounds());
587 end = location = target->GetBoundsInRootWindow().CenterPoint();
589 generator.GestureScrollSequence(location, end,
590 base::TimeDelta::FromMilliseconds(5),
592 RunAllPendingInMessageLoop();
594 // Verify that the window has moved after the gesture.
595 gfx::Rect expected_bounds(old_bounds);
596 expected_bounds.Offset(gfx::Vector2d(-100, 0));
597 EXPECT_EQ(expected_bounds.ToString(), target->bounds().ToString());
599 // Verify that the window did not snap left.
600 EXPECT_NE(snapped_bounds.ToString(), target->bounds().ToString());
604 // Tests that dragging multiple windows at the same time is not allowed.
605 TEST_F(ToplevelWindowEventHandlerTest, GestureDragMultipleWindows) {
606 scoped_ptr<aura::Window> target(
607 CreateTestWindowInShellWithDelegate(
608 new TestWindowDelegate(HTCAPTION),
610 gfx::Rect(0, 0, 100, 100)));
611 scoped_ptr<aura::Window> notmoved(
612 CreateTestWindowInShellWithDelegate(
613 new TestWindowDelegate(HTCAPTION),
614 1, gfx::Rect(100, 0, 100, 100)));
616 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
618 gfx::Rect old_bounds = target->bounds();
619 gfx::Point location(5, 5);
620 target->SetProperty(aura::client::kCanMaximizeKey, true);
622 // Send some touch events to start dragging |target|.
623 generator.MoveTouch(location);
624 generator.PressTouch();
625 location.Offset(40, 5);
626 generator.MoveTouch(location);
628 // Try to drag |notmoved| window. This should not move the window.
630 gfx::Rect bounds = notmoved->bounds();
631 aura::test::EventGenerator gen(Shell::GetPrimaryRootWindow(),
633 gfx::Point start = notmoved->bounds().origin() + gfx::Vector2d(10, 10);
634 gfx::Point end = start + gfx::Vector2d(100, 10);
635 gen.GestureScrollSequence(start, end,
636 base::TimeDelta::FromMilliseconds(10),
638 EXPECT_EQ(bounds.ToString(), notmoved->bounds().ToString());
642 // Verifies pressing escape resets the bounds to the original bounds.
643 // Disabled crbug.com/166219.
645 #define MAYBE_EscapeReverts DISABLED_EscapeReverts
647 #define MAYBE_EscapeReverts EscapeReverts
649 TEST_F(ToplevelWindowEventHandlerTest, MAYBE_EscapeReverts) {
650 scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT));
651 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
653 generator.PressLeftButton();
654 generator.MoveMouseBy(10, 11);
656 // Execute any scheduled draws so that pending mouse events are processed.
657 RunAllPendingInMessageLoop();
659 EXPECT_EQ("0,0 110x111", target->bounds().ToString());
660 generator.PressKey(ui::VKEY_ESCAPE, 0);
661 generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
662 EXPECT_EQ("0,0 100x100", target->bounds().ToString());
665 // Verifies window minimization/maximization completes drag.
666 // Disabled crbug.com/166219.
668 #define MAYBE_MinimizeMaximizeCompletes DISABLED_MinimizeMaximizeCompletes
670 #define MAYBE_MinimizeMaximizeCompletes MinimizeMaximizeCompletes
672 TEST_F(ToplevelWindowEventHandlerTest, MAYBE_MinimizeMaximizeCompletes) {
673 // Once window is minimized, window dragging completes.
675 scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
677 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
679 generator.PressLeftButton();
680 generator.MoveMouseBy(10, 11);
681 RunAllPendingInMessageLoop();
682 EXPECT_EQ("10,11 100x100", target->bounds().ToString());
683 wm::WindowState* window_state = wm::GetWindowState(target.get());
684 window_state->Minimize();
685 window_state->Restore();
687 generator.PressLeftButton();
688 generator.MoveMouseBy(10, 11);
689 RunAllPendingInMessageLoop();
690 EXPECT_EQ("10,11 100x100", target->bounds().ToString());
693 // Once window is maximized, window dragging completes.
695 scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
697 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
699 generator.PressLeftButton();
700 generator.MoveMouseBy(10, 11);
701 RunAllPendingInMessageLoop();
702 EXPECT_EQ("10,11 100x100", target->bounds().ToString());
703 wm::WindowState* window_state = wm::GetWindowState(target.get());
704 window_state->Maximize();
705 window_state->Restore();
707 generator.PressLeftButton();
708 generator.MoveMouseBy(10, 11);
709 RunAllPendingInMessageLoop();
710 EXPECT_EQ("10,11 100x100", target->bounds().ToString());
714 // Verifies that a drag cannot be started via
715 // aura::client::WindowMoveClient::RunMoveLoop() while another drag is already
717 TEST_F(ToplevelWindowEventHandlerTest, RunMoveLoopFailsDuringInProgressDrag) {
718 scoped_ptr<aura::Window> window1(CreateWindow(HTCAPTION));
719 EXPECT_EQ("0,0 100x100", window1->bounds().ToString());
720 scoped_ptr<aura::Window> window2(CreateWindow(HTCAPTION));
722 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
725 generator.PressLeftButton();
726 generator.MoveMouseBy(10, 11);
727 EXPECT_EQ("10,11 100x100", window1->bounds().ToString());
729 aura::client::WindowMoveClient* move_client =
730 aura::client::GetWindowMoveClient(window2->GetRootWindow());
731 EXPECT_EQ(aura::client::MOVE_CANCELED,
732 move_client->RunMoveLoop(window2.get(), gfx::Vector2d(),
733 aura::client::WINDOW_MOVE_SOURCE_MOUSE));
735 generator.ReleaseLeftButton();
736 EXPECT_EQ("10,11 100x100", window1->bounds().ToString());
739 // Showing the resize shadows when the mouse is over the window edges is tested
740 // in resize_shadow_and_cursor_test.cc