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