Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / ash / wm / toplevel_window_event_handler_unittest.cc
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/toplevel_window_event_handler.h"
6
7 #include "ash/root_window_controller.h"
8 #include "ash/shell.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 "testing/gtest/include/gtest/gtest.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/test/aura_test_base.h"
22 #include "ui/aura/test/test_window_delegate.h"
23 #include "ui/aura/window_event_dispatcher.h"
24 #include "ui/base/hit_test.h"
25 #include "ui/events/event.h"
26 #include "ui/events/test/event_generator.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/wm/core/window_util.h"
29 #include "ui/wm/public/window_move_client.h"
30
31 #if defined(OS_WIN)
32 // Windows headers define macros for these function names which screw with us.
33 #if defined(CreateWindow)
34 #undef CreateWindow
35 #endif
36 #endif
37
38 namespace ash {
39 namespace test {
40
41 namespace {
42
43 // A simple window delegate that returns the specified hit-test code when
44 // requested and applies a minimum size constraint if there is one.
45 class TestWindowDelegate : public aura::test::TestWindowDelegate {
46  public:
47   explicit TestWindowDelegate(int hittest_code) {
48     set_window_component(hittest_code);
49   }
50   ~TestWindowDelegate() override {}
51
52  private:
53   // Overridden from aura::Test::TestWindowDelegate:
54   void OnWindowDestroyed(aura::Window* window) override { delete this; }
55
56   DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
57 };
58
59 class ToplevelWindowEventHandlerTest : public AshTestBase {
60  public:
61   ToplevelWindowEventHandlerTest() {}
62   ~ToplevelWindowEventHandlerTest() override {}
63
64  protected:
65   aura::Window* CreateWindow(int hittest_code) {
66     TestWindowDelegate* d1 = new TestWindowDelegate(hittest_code);
67     aura::Window* w1 = new aura::Window(d1);
68     w1->SetType(ui::wm::WINDOW_TYPE_NORMAL);
69     w1->set_id(1);
70     w1->Init(aura::WINDOW_LAYER_TEXTURED);
71     aura::Window* parent = Shell::GetContainer(
72         Shell::GetPrimaryRootWindow(), kShellWindowId_AlwaysOnTopContainer);
73     parent->AddChild(w1);
74     w1->SetBounds(gfx::Rect(0, 0, 100, 100));
75     w1->Show();
76     return w1;
77   }
78
79   void DragFromCenterBy(aura::Window* window, int dx, int dy) {
80     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), window);
81     generator.DragMouseBy(dx, dy);
82   }
83
84   void TouchDragFromCenterBy(aura::Window* window, int dx, int dy) {
85     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), window);
86     generator.PressMoveAndReleaseTouchBy(dx, dy);
87   }
88
89   scoped_ptr<ToplevelWindowEventHandler> handler_;
90
91  private:
92   DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventHandlerTest);
93 };
94
95 }
96
97 TEST_F(ToplevelWindowEventHandlerTest, Caption) {
98   scoped_ptr<aura::Window> w1(CreateWindow(HTCAPTION));
99   gfx::Size size = w1->bounds().size();
100   DragFromCenterBy(w1.get(), 100, 100);
101   // Position should have been offset by 100,100.
102   EXPECT_EQ("100,100", w1->bounds().origin().ToString());
103   // Size should not have.
104   EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
105
106   TouchDragFromCenterBy(w1.get(), 100, 100);
107   // Position should have been offset by 100,100.
108   EXPECT_EQ("200,200", w1->bounds().origin().ToString());
109   // Size should not have.
110   EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
111 }
112
113 TEST_F(ToplevelWindowEventHandlerTest, BottomRight) {
114   scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMRIGHT));
115   gfx::Point position = w1->bounds().origin();
116   DragFromCenterBy(w1.get(), 100, 100);
117   // Position should not have changed.
118   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
119   // Size should have increased by 100,100.
120   EXPECT_EQ(gfx::Size(200, 200).ToString(), w1->bounds().size().ToString());
121 }
122
123 TEST_F(ToplevelWindowEventHandlerTest, GrowBox) {
124   scoped_ptr<aura::Window> w1(CreateWindow(HTGROWBOX));
125   TestWindowDelegate* window_delegate =
126       static_cast<TestWindowDelegate*>(w1->delegate());
127   window_delegate->set_minimum_size(gfx::Size(40, 40));
128
129   gfx::Point position = w1->bounds().origin();
130   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
131   generator.MoveMouseToCenterOf(w1.get());
132   generator.DragMouseBy(100, 100);
133   // Position should not have changed.
134   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
135   // Size should have increased by 100,100.
136   EXPECT_EQ(gfx::Size(200, 200).ToString(), w1->bounds().size().ToString());
137
138   // Shrink the wnidow by (-100, -100).
139   generator.DragMouseBy(-100, -100);
140   // Position should not have changed.
141   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
142   // Size should have decreased by 100,100.
143   EXPECT_EQ(gfx::Size(100, 100).ToString(), w1->bounds().size().ToString());
144
145   // Enforce minimum size.
146   generator.DragMouseBy(-60, -60);
147   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
148   EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
149 }
150
151 TEST_F(ToplevelWindowEventHandlerTest, Right) {
152   scoped_ptr<aura::Window> w1(CreateWindow(HTRIGHT));
153   gfx::Point position = w1->bounds().origin();
154   DragFromCenterBy(w1.get(), 100, 100);
155   // Position should not have changed.
156   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
157   // Size should have increased by 100,0.
158   EXPECT_EQ(gfx::Size(200, 100).ToString(), w1->bounds().size().ToString());
159 }
160
161 TEST_F(ToplevelWindowEventHandlerTest, Bottom) {
162   scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOM));
163   gfx::Point position = w1->bounds().origin();
164   DragFromCenterBy(w1.get(), 100, 100);
165   // Position should not have changed.
166   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
167   // Size should have increased by 0,100.
168   EXPECT_EQ(gfx::Size(100, 200).ToString(), w1->bounds().size().ToString());
169 }
170
171 TEST_F(ToplevelWindowEventHandlerTest, TopRight) {
172   scoped_ptr<aura::Window> w1(CreateWindow(HTTOPRIGHT));
173   DragFromCenterBy(w1.get(), -50, 50);
174   // Position should have been offset by 0,50.
175   EXPECT_EQ(gfx::Point(0, 50).ToString(), w1->bounds().origin().ToString());
176   // Size should have decreased by 50,50.
177   EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
178 }
179
180 TEST_F(ToplevelWindowEventHandlerTest, Top) {
181   scoped_ptr<aura::Window> w1(CreateWindow(HTTOP));
182   DragFromCenterBy(w1.get(), 50, 50);
183   // Position should have been offset by 0,50.
184   EXPECT_EQ(gfx::Point(0, 50).ToString(), w1->bounds().origin().ToString());
185   // Size should have decreased by 0,50.
186   EXPECT_EQ(gfx::Size(100, 50).ToString(), w1->bounds().size().ToString());
187 }
188
189 TEST_F(ToplevelWindowEventHandlerTest, Left) {
190   scoped_ptr<aura::Window> w1(CreateWindow(HTLEFT));
191   DragFromCenterBy(w1.get(), 50, 50);
192   // Position should have been offset by 50,0.
193   EXPECT_EQ(gfx::Point(50, 0).ToString(), w1->bounds().origin().ToString());
194   // Size should have decreased by 50,0.
195   EXPECT_EQ(gfx::Size(50, 100).ToString(), w1->bounds().size().ToString());
196 }
197
198 TEST_F(ToplevelWindowEventHandlerTest, BottomLeft) {
199   scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMLEFT));
200   DragFromCenterBy(w1.get(), 50, -50);
201   // Position should have been offset by 50,0.
202   EXPECT_EQ(gfx::Point(50, 0).ToString(), w1->bounds().origin().ToString());
203   // Size should have decreased by 50,50.
204   EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
205 }
206
207 TEST_F(ToplevelWindowEventHandlerTest, TopLeft) {
208   scoped_ptr<aura::Window> w1(CreateWindow(HTTOPLEFT));
209   DragFromCenterBy(w1.get(), 50, 50);
210   // Position should have been offset by 50,50.
211   EXPECT_EQ(gfx::Point(50, 50).ToString(), w1->bounds().origin().ToString());
212   // Size should have decreased by 50,50.
213   EXPECT_EQ(gfx::Size(50, 50).ToString(), w1->bounds().size().ToString());
214 }
215
216 TEST_F(ToplevelWindowEventHandlerTest, Client) {
217   scoped_ptr<aura::Window> w1(CreateWindow(HTCLIENT));
218   gfx::Rect bounds = w1->bounds();
219   DragFromCenterBy(w1.get(), 100, 100);
220   // Neither position nor size should have changed.
221   EXPECT_EQ(bounds.ToString(), w1->bounds().ToString());
222 }
223
224 TEST_F(ToplevelWindowEventHandlerTest, LeftPastMinimum) {
225   scoped_ptr<aura::Window> w1(CreateWindow(HTLEFT));
226   TestWindowDelegate* window_delegate =
227       static_cast<TestWindowDelegate*>(w1->delegate());
228   window_delegate->set_minimum_size(gfx::Size(40, 40));
229
230   // Simulate a large left-to-right drag.  Window width should be clamped to
231   // minimum and position change should be limited as well.
232   DragFromCenterBy(w1.get(), 333, 0);
233   EXPECT_EQ(gfx::Point(60, 0).ToString(), w1->bounds().origin().ToString());
234   EXPECT_EQ(gfx::Size(40, 100).ToString(), w1->bounds().size().ToString());
235 }
236
237 TEST_F(ToplevelWindowEventHandlerTest, RightPastMinimum) {
238   scoped_ptr<aura::Window> w1(CreateWindow(HTRIGHT));
239   TestWindowDelegate* window_delegate =
240       static_cast<TestWindowDelegate*>(w1->delegate());
241   window_delegate->set_minimum_size(gfx::Size(40, 40));
242   gfx::Point position = w1->bounds().origin();
243
244   // Simulate a large right-to-left drag.  Window width should be clamped to
245   // minimum and position should not change.
246   DragFromCenterBy(w1.get(), -333, 0);
247   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
248   EXPECT_EQ(gfx::Size(40, 100).ToString(), w1->bounds().size().ToString());
249 }
250
251 TEST_F(ToplevelWindowEventHandlerTest, TopLeftPastMinimum) {
252   scoped_ptr<aura::Window> w1(CreateWindow(HTTOPLEFT));
253   TestWindowDelegate* window_delegate =
254       static_cast<TestWindowDelegate*>(w1->delegate());
255   window_delegate->set_minimum_size(gfx::Size(40, 40));
256
257   // Simulate a large top-left to bottom-right drag.  Window width should be
258   // clamped to minimum and position should be limited.
259   DragFromCenterBy(w1.get(), 333, 444);
260   EXPECT_EQ(gfx::Point(60, 60).ToString(), w1->bounds().origin().ToString());
261   EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
262 }
263
264 TEST_F(ToplevelWindowEventHandlerTest, TopRightPastMinimum) {
265   scoped_ptr<aura::Window> w1(CreateWindow(HTTOPRIGHT));
266   TestWindowDelegate* window_delegate =
267       static_cast<TestWindowDelegate*>(w1->delegate());
268   window_delegate->set_minimum_size(gfx::Size(40, 40));
269
270   // Simulate a large top-right to bottom-left drag.  Window size should be
271   // clamped to minimum, x position should not change, and y position should
272   // be clamped.
273   DragFromCenterBy(w1.get(), -333, 444);
274   EXPECT_EQ(gfx::Point(0, 60).ToString(), w1->bounds().origin().ToString());
275   EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
276 }
277
278 TEST_F(ToplevelWindowEventHandlerTest, BottomLeftPastMinimum) {
279   scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMLEFT));
280   TestWindowDelegate* window_delegate =
281       static_cast<TestWindowDelegate*>(w1->delegate());
282   window_delegate->set_minimum_size(gfx::Size(40, 40));
283
284   // Simulate a large bottom-left to top-right drag.  Window size should be
285   // clamped to minimum, x position should be clamped, and y position should
286   // not change.
287   DragFromCenterBy(w1.get(), 333, -444);
288   EXPECT_EQ(gfx::Point(60, 0).ToString(), w1->bounds().origin().ToString());
289   EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
290 }
291
292 TEST_F(ToplevelWindowEventHandlerTest, BottomRightPastMinimum) {
293   scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMRIGHT));
294   TestWindowDelegate* window_delegate =
295       static_cast<TestWindowDelegate*>(w1->delegate());
296   window_delegate->set_minimum_size(gfx::Size(40, 40));
297   gfx::Point position = w1->bounds().origin();
298
299   // Simulate a large bottom-right to top-left drag.  Window size should be
300   // clamped to minimum and position should not change.
301   DragFromCenterBy(w1.get(), -333, -444);
302   EXPECT_EQ(position.ToString(), w1->bounds().origin().ToString());
303   EXPECT_EQ(gfx::Size(40, 40).ToString(), w1->bounds().size().ToString());
304 }
305
306 TEST_F(ToplevelWindowEventHandlerTest, BottomRightWorkArea) {
307   scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT));
308   gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
309       target.get()).work_area();
310   gfx::Point position = target->bounds().origin();
311   // Drag further than work_area bottom.
312   DragFromCenterBy(target.get(), 100, work_area.height());
313   // Position should not have changed.
314   EXPECT_EQ(position.ToString(), target->bounds().origin().ToString());
315   // Size should have increased by 100, work_area.height() - target->bounds.y()
316   EXPECT_EQ(
317       gfx::Size(200, work_area.height() - target->bounds().y()).ToString(),
318       target->bounds().size().ToString());
319 }
320
321 TEST_F(ToplevelWindowEventHandlerTest, BottomLeftWorkArea) {
322   scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMLEFT));
323   gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
324       target.get()).work_area();
325   gfx::Point position = target->bounds().origin();
326   // Drag further than work_area bottom.
327   DragFromCenterBy(target.get(), -30, work_area.height());
328   // origin is now at 70, 100.
329   EXPECT_EQ(position.x() - 30, target->bounds().x());
330   EXPECT_EQ(position.y(), target->bounds().y());
331   // Size should have increased by 30, work_area.height() - target->bounds.y()
332   EXPECT_EQ(
333       gfx::Size(130, work_area.height() - target->bounds().y()).ToString(),
334       target->bounds().size().ToString());
335 }
336
337 TEST_F(ToplevelWindowEventHandlerTest, BottomWorkArea) {
338   scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOM));
339   gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
340       target.get()).work_area();
341   gfx::Point position = target->bounds().origin();
342   // Drag further than work_area bottom.
343   DragFromCenterBy(target.get(), 0, work_area.height());
344   // Position should not have changed.
345   EXPECT_EQ(position.ToString(), target->bounds().origin().ToString());
346   // Size should have increased by 0, work_area.height() - target->bounds.y()
347   EXPECT_EQ(
348       gfx::Size(100, work_area.height() - target->bounds().y()).ToString(),
349       target->bounds().size().ToString());
350 }
351
352 TEST_F(ToplevelWindowEventHandlerTest, DontDragIfModalChild) {
353   scoped_ptr<aura::Window> w1(CreateWindow(HTCAPTION));
354   scoped_ptr<aura::Window> w2(CreateWindow(HTCAPTION));
355   w2->SetBounds(gfx::Rect(100, 0, 100, 100));
356   w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
357   ::wm::AddTransientChild(w1.get(), w2.get());
358   gfx::Size size = w1->bounds().size();
359
360   // Attempt to drag w1, position and size should not change because w1 has a
361   // modal child.
362   DragFromCenterBy(w1.get(), 100, 100);
363   EXPECT_EQ("0,0", w1->bounds().origin().ToString());
364   EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
365
366   TouchDragFromCenterBy(w1.get(), 100, 100);
367   EXPECT_EQ("0,0", w1->bounds().origin().ToString());
368   EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
369 }
370
371 // Verifies we don't let windows drag to a -y location.
372 TEST_F(ToplevelWindowEventHandlerTest, DontDragToNegativeY) {
373   scoped_ptr<aura::Window> target(CreateWindow(HTTOP));
374   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
375                                      target.get());
376   generator.MoveMouseTo(0, 5);
377   generator.DragMouseBy(0, -5);
378   // The y location and height should not have changed.
379   EXPECT_EQ(0, target->bounds().y());
380   EXPECT_EQ(100, target->bounds().height());
381 }
382
383 // Verifies we don't let windows go bigger than the display width.
384 TEST_F(ToplevelWindowEventHandlerTest, DontGotWiderThanScreen) {
385   scoped_ptr<aura::Window> target(CreateWindow(HTRIGHT));
386   gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
387       target.get()).bounds();
388   DragFromCenterBy(target.get(), work_area.width() * 2, 0);
389   // The y location and height should not have changed.
390   EXPECT_EQ(work_area.width(), target->bounds().width());
391 }
392
393 // Verifies that touch-gestures drag the window correctly.
394 TEST_F(ToplevelWindowEventHandlerTest, GestureDrag) {
395   scoped_ptr<aura::Window> target(
396       CreateTestWindowInShellWithDelegate(
397           new TestWindowDelegate(HTCAPTION),
398           0,
399           gfx::Rect(0, 0, 100, 100)));
400   wm::WindowState* window_state = wm::GetWindowState(target.get());
401   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
402                                      target.get());
403   gfx::Rect old_bounds = target->bounds();
404   gfx::Point location(5, 5);
405   target->SetProperty(aura::client::kCanMaximizeKey, true);
406
407   gfx::Point end = location;
408
409   // Snap right;
410   end.Offset(100, 0);
411   generator.GestureScrollSequence(location, end,
412       base::TimeDelta::FromMilliseconds(5),
413       10);
414   RunAllPendingInMessageLoop();
415
416   // Verify that the window has moved after the gesture.
417   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
418   EXPECT_EQ(wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED, window_state->GetStateType());
419
420   old_bounds = target->bounds();
421
422   // Snap left.
423   end = location = target->GetBoundsInRootWindow().CenterPoint();
424   end.Offset(-100, 0);
425   generator.GestureScrollSequence(location, end,
426       base::TimeDelta::FromMilliseconds(5),
427       10);
428   RunAllPendingInMessageLoop();
429
430   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
431   EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
432
433   gfx::Rect bounds_before_maximization = target->bounds();
434   bounds_before_maximization.Offset(0, 100);
435   target->SetBounds(bounds_before_maximization);
436   old_bounds = target->bounds();
437
438   // Maximize.
439   end = location = target->GetBoundsInRootWindow().CenterPoint();
440   end.Offset(0, -100);
441   generator.GestureScrollSequence(location, end,
442       base::TimeDelta::FromMilliseconds(5),
443       10);
444   RunAllPendingInMessageLoop();
445
446   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
447   EXPECT_TRUE(window_state->IsMaximized());
448   EXPECT_EQ(old_bounds.ToString(),
449             window_state->GetRestoreBoundsInScreen().ToString());
450
451   window_state->Restore();
452   target->SetBounds(old_bounds);
453
454   // Minimize.
455   end = location = target->GetBoundsInRootWindow().CenterPoint();
456   end.Offset(0, 100);
457   generator.GestureScrollSequence(location, end,
458       base::TimeDelta::FromMilliseconds(5),
459       10);
460   RunAllPendingInMessageLoop();
461   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
462   EXPECT_TRUE(window_state->IsMinimized());
463   EXPECT_TRUE(window_state->unminimize_to_restore_bounds());
464   EXPECT_EQ(old_bounds.ToString(),
465             window_state->GetRestoreBoundsInScreen().ToString());
466 }
467
468 // Tests that a gesture cannot minimize an unminimizeable window.
469 TEST_F(ToplevelWindowEventHandlerTest,
470        GestureAttemptMinimizeUnminimizeableWindow) {
471   scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
472   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
473                                      target.get());
474   gfx::Rect old_bounds = target->bounds();
475   gfx::Point location(5, 5);
476   target->SetProperty(aura::client::kCanMaximizeKey, true);
477   target->SetProperty(aura::client::kCanMinimizeKey, false);
478
479   gfx::Point end = location;
480   end.Offset(0, 100);
481   generator.GestureScrollSequence(location, end,
482       base::TimeDelta::FromMilliseconds(5),
483       10);
484   RunAllPendingInMessageLoop();
485   EXPECT_FALSE(wm::GetWindowState(target.get())->IsMinimized());
486 }
487
488 TEST_F(ToplevelWindowEventHandlerTest, GestureDragToRestore) {
489   scoped_ptr<aura::Window> window(
490       CreateTestWindowInShellWithDelegate(
491           new TestWindowDelegate(HTCAPTION),
492           0,
493           gfx::Rect(10, 20, 30, 40)));
494   window->Show();
495   wm::WindowState* window_state = wm::GetWindowState(window.get());
496   window_state->Activate();
497
498   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
499                                      window.get());
500   gfx::Rect old_bounds = window->bounds();
501   gfx::Point location, end;
502   end = location = window->GetBoundsInRootWindow().CenterPoint();
503   end.Offset(0, 100);
504   generator.GestureScrollSequence(location, end,
505       base::TimeDelta::FromMilliseconds(5),
506       10);
507   RunAllPendingInMessageLoop();
508   EXPECT_NE(old_bounds.ToString(), window->bounds().ToString());
509   EXPECT_TRUE(window_state->IsMinimized());
510   EXPECT_TRUE(window_state->unminimize_to_restore_bounds());
511   EXPECT_EQ(old_bounds.ToString(),
512             window_state->GetRestoreBoundsInScreen().ToString());
513 }
514
515 // Tests that an unresizable window cannot be dragged or snapped using gestures.
516 TEST_F(ToplevelWindowEventHandlerTest, GestureDragForUnresizableWindow) {
517   scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
518   wm::WindowState* window_state = wm::GetWindowState(target.get());
519
520   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
521                                      target.get());
522   gfx::Rect old_bounds = target->bounds();
523   gfx::Point location(5, 5);
524
525   target->SetProperty(aura::client::kCanResizeKey, false);
526
527   gfx::Point end = location;
528
529   // Try to snap right. The window is not resizable. So it should not snap.
530   end.Offset(100, 0);
531   generator.GestureScrollSequence(location, end,
532       base::TimeDelta::FromMilliseconds(5),
533       10);
534   RunAllPendingInMessageLoop();
535
536   // Verify that the window has moved after the gesture.
537   gfx::Rect expected_bounds(old_bounds);
538   expected_bounds.Offset(gfx::Vector2d(100, 0));
539   EXPECT_EQ(expected_bounds.ToString(), target->bounds().ToString());
540
541   // Verify that the window did not snap left.
542   EXPECT_TRUE(window_state->IsNormalStateType());
543
544   old_bounds = target->bounds();
545
546   // Try to snap left. It should not snap.
547   end = location = target->GetBoundsInRootWindow().CenterPoint();
548   end.Offset(-100, 0);
549   generator.GestureScrollSequence(location, end,
550       base::TimeDelta::FromMilliseconds(5),
551       10);
552   RunAllPendingInMessageLoop();
553
554   // Verify that the window has moved after the gesture.
555   expected_bounds = old_bounds;
556   expected_bounds.Offset(gfx::Vector2d(-100, 0));
557   EXPECT_EQ(expected_bounds.ToString(), target->bounds().ToString());
558
559   // Verify that the window did not snap left.
560   EXPECT_TRUE(window_state->IsNormalStateType());
561 }
562
563 // Tests that dragging multiple windows at the same time is not allowed.
564 TEST_F(ToplevelWindowEventHandlerTest, GestureDragMultipleWindows) {
565   scoped_ptr<aura::Window> target(
566       CreateTestWindowInShellWithDelegate(
567           new TestWindowDelegate(HTCAPTION),
568           0,
569           gfx::Rect(0, 0, 100, 100)));
570   scoped_ptr<aura::Window> notmoved(
571       CreateTestWindowInShellWithDelegate(
572           new TestWindowDelegate(HTCAPTION),
573           1, gfx::Rect(100, 0, 100, 100)));
574
575   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
576                                      target.get());
577   gfx::Rect old_bounds = target->bounds();
578   gfx::Point location(5, 5);
579   target->SetProperty(aura::client::kCanMaximizeKey, true);
580
581   // Send some touch events to start dragging |target|.
582   generator.MoveTouch(location);
583   generator.PressTouch();
584   location.Offset(40, 5);
585   generator.MoveTouch(location);
586
587   // Try to drag |notmoved| window. This should not move the window.
588   {
589     gfx::Rect bounds = notmoved->bounds();
590     ui::test::EventGenerator gen(Shell::GetPrimaryRootWindow(), notmoved.get());
591     gfx::Point start = notmoved->bounds().origin() + gfx::Vector2d(10, 10);
592     gfx::Point end = start + gfx::Vector2d(100, 10);
593     gen.GestureScrollSequence(start, end,
594         base::TimeDelta::FromMilliseconds(10),
595         10);
596     EXPECT_EQ(bounds.ToString(), notmoved->bounds().ToString());
597   }
598 }
599
600 // Verifies pressing escape resets the bounds to the original bounds.
601 // Disabled crbug.com/166219.
602 #if defined(OS_WIN)
603 #define MAYBE_EscapeReverts DISABLED_EscapeReverts
604 #else
605 #define MAYBE_EscapeReverts EscapeReverts
606 #endif
607 TEST_F(ToplevelWindowEventHandlerTest, MAYBE_EscapeReverts) {
608   scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT));
609   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
610                                      target.get());
611   generator.PressLeftButton();
612   generator.MoveMouseBy(10, 11);
613
614   // Execute any scheduled draws so that pending mouse events are processed.
615   RunAllPendingInMessageLoop();
616
617   EXPECT_EQ("0,0 110x111", target->bounds().ToString());
618   generator.PressKey(ui::VKEY_ESCAPE, 0);
619   generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
620   EXPECT_EQ("0,0 100x100", target->bounds().ToString());
621 }
622
623 // Verifies window minimization/maximization completes drag.
624 // Disabled crbug.com/166219.
625 #if defined(OS_WIN)
626 #define MAYBE_MinimizeMaximizeCompletes DISABLED_MinimizeMaximizeCompletes
627 #else
628 #define MAYBE_MinimizeMaximizeCompletes MinimizeMaximizeCompletes
629 #endif
630 TEST_F(ToplevelWindowEventHandlerTest, MAYBE_MinimizeMaximizeCompletes) {
631   // Once window is minimized, window dragging completes.
632   {
633     scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
634     target->Focus();
635     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
636                                        target.get());
637     generator.PressLeftButton();
638     generator.MoveMouseBy(10, 11);
639     RunAllPendingInMessageLoop();
640     EXPECT_EQ("10,11 100x100", target->bounds().ToString());
641     wm::WindowState* window_state = wm::GetWindowState(target.get());
642     window_state->Minimize();
643     window_state->Restore();
644
645     generator.PressLeftButton();
646     generator.MoveMouseBy(10, 11);
647     RunAllPendingInMessageLoop();
648     EXPECT_EQ("10,11 100x100", target->bounds().ToString());
649   }
650
651   // Once window is maximized, window dragging completes.
652   {
653     scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION));
654     target->Focus();
655     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
656                                        target.get());
657     generator.PressLeftButton();
658     generator.MoveMouseBy(10, 11);
659     RunAllPendingInMessageLoop();
660     EXPECT_EQ("10,11 100x100", target->bounds().ToString());
661     wm::WindowState* window_state = wm::GetWindowState(target.get());
662     window_state->Maximize();
663     window_state->Restore();
664
665     generator.PressLeftButton();
666     generator.MoveMouseBy(10, 11);
667     RunAllPendingInMessageLoop();
668     EXPECT_EQ("10,11 100x100", target->bounds().ToString());
669   }
670 }
671
672 // Verifies that a drag cannot be started via
673 // aura::client::WindowMoveClient::RunMoveLoop() while another drag is already
674 // in progress.
675 TEST_F(ToplevelWindowEventHandlerTest, RunMoveLoopFailsDuringInProgressDrag) {
676   scoped_ptr<aura::Window> window1(CreateWindow(HTCAPTION));
677   EXPECT_EQ("0,0 100x100", window1->bounds().ToString());
678   scoped_ptr<aura::Window> window2(CreateWindow(HTCAPTION));
679
680   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
681                                      window1.get());
682   window1->Focus();
683   generator.PressLeftButton();
684   generator.MoveMouseBy(10, 11);
685   EXPECT_EQ("10,11 100x100", window1->bounds().ToString());
686
687   aura::client::WindowMoveClient* move_client =
688       aura::client::GetWindowMoveClient(window2->GetRootWindow());
689   EXPECT_EQ(aura::client::MOVE_CANCELED,
690             move_client->RunMoveLoop(window2.get(), gfx::Vector2d(),
691                 aura::client::WINDOW_MOVE_SOURCE_MOUSE));
692
693   generator.ReleaseLeftButton();
694   EXPECT_EQ("10,11 100x100", window1->bounds().ToString());
695 }
696
697 namespace {
698
699 void SendMouseReleaseAndReleaseCapture(ui::test::EventGenerator* generator,
700                                        aura::Window* window) {
701   generator->ReleaseLeftButton();
702   window->ReleaseCapture();
703 }
704
705 }  // namespace
706
707 // Test that a drag is successful even if ET_MOUSE_CAPTURE_CHANGED is sent
708 // immediately after the mouse release. views::Widget has this behavior.
709 TEST_F(ToplevelWindowEventHandlerTest, CaptureLossAfterMouseRelease) {
710   scoped_ptr<aura::Window> window(CreateWindow(HTNOWHERE));
711   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
712                                      window.get());
713   generator.PressLeftButton();
714   window->SetCapture();
715
716   aura::client::WindowMoveClient* move_client =
717       aura::client::GetWindowMoveClient(window->GetRootWindow());
718   base::MessageLoopForUI::current()->PostTask(
719       FROM_HERE,
720       base::Bind(&SendMouseReleaseAndReleaseCapture,
721                  base::Unretained(&generator),
722                  base::Unretained(window.get())));
723   EXPECT_EQ(aura::client::MOVE_SUCCESSFUL,
724             move_client->RunMoveLoop(window.get(), gfx::Vector2d(),
725                 aura::client::WINDOW_MOVE_SOURCE_MOUSE));
726 }
727
728 // Showing the resize shadows when the mouse is over the window edges is tested
729 // in resize_shadow_and_cursor_test.cc
730
731 }  // namespace test
732 }  // namespace ash