Home | History | Annotate | Download | only in wm
      1 // Copyright 2013 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/ash_constants.h"
      6 #include "ash/frame/custom_frame_view_ash.h"
      7 #include "ash/shell.h"
      8 #include "ash/test/ash_test_base.h"
      9 #include "ash/test/cursor_manager_test_api.h"
     10 #include "ash/wm/resize_shadow.h"
     11 #include "ash/wm/resize_shadow_controller.h"
     12 #include "ash/wm/window_state.h"
     13 #include "base/bind.h"
     14 #include "ui/aura/window_event_dispatcher.h"
     15 #include "ui/base/cursor/cursor.h"
     16 #include "ui/base/hit_test.h"
     17 #include "ui/events/test/event_generator.h"
     18 #include "ui/views/widget/widget.h"
     19 #include "ui/views/widget/widget_delegate.h"
     20 
     21 namespace ash {
     22 namespace test {
     23 
     24 namespace {
     25 
     26 // views::WidgetDelegate which uses ash::CustomFrameViewAsh.
     27 class TestWidgetDelegate : public views::WidgetDelegateView {
     28  public:
     29   TestWidgetDelegate() {}
     30   virtual ~TestWidgetDelegate() {}
     31 
     32   // views::WidgetDelegateView overrides:
     33   virtual bool CanResize() const OVERRIDE {
     34     return true;
     35   }
     36   virtual bool CanMaximize() const OVERRIDE {
     37     return true;
     38   }
     39   virtual bool CanMinimize() const OVERRIDE {
     40     return true;
     41   }
     42   virtual views::NonClientFrameView* CreateNonClientFrameView(
     43       views::Widget* widget) OVERRIDE {
     44     return new ash::CustomFrameViewAsh(widget);
     45   }
     46 
     47  private:
     48   DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
     49 };
     50 
     51 }  // namespace
     52 
     53 // The test tests that the mouse cursor is changed and that the resize shadows
     54 // are shown when the mouse is hovered over the window edge.
     55 class ResizeShadowAndCursorTest : public AshTestBase {
     56  public:
     57   ResizeShadowAndCursorTest() {}
     58   virtual ~ResizeShadowAndCursorTest() {}
     59 
     60   // AshTestBase override:
     61   virtual void SetUp() OVERRIDE {
     62     AshTestBase::SetUp();
     63 
     64     views::Widget* widget(views::Widget::CreateWindowWithContextAndBounds(
     65         new TestWidgetDelegate(), CurrentContext(), gfx::Rect(0, 0, 200, 100)));
     66     widget->Show();
     67     window_ = widget->GetNativeView();
     68 
     69     // Add a child window to |window_| in order to properly test that the resize
     70     // handles and the resize shadows are shown when the mouse is
     71     // ash::kResizeInsideBoundsSize inside of |window_|'s edges.
     72     aura::Window* child = CreateTestWindowInShell(
     73         SK_ColorWHITE, 0, gfx::Rect(0, 10, 200, 90));
     74     window_->AddChild(child);
     75   }
     76 
     77   // Returns the hit test code if there is a resize shadow. Returns HTNOWHERE if
     78   // there is no resize shadow.
     79   int ResizeShadowHitTest() const {
     80     ash::ResizeShadow* resize_shadow = ash::Shell::GetInstance()
     81                                            ->resize_shadow_controller()
     82                                            ->GetShadowForWindowForTest(window_);
     83     return resize_shadow ? resize_shadow->GetLastHitTestForTest() : HTNOWHERE;
     84   }
     85 
     86   // Returns true if there is a resize shadow.
     87   bool HasResizeShadow() const {
     88     return ResizeShadowHitTest() != HTNOWHERE;
     89   }
     90 
     91   // Returns the current cursor type.
     92   int GetCurrentCursorType() const {
     93     CursorManagerTestApi test_api(ash::Shell::GetInstance()->cursor_manager());
     94     return test_api.GetCurrentCursor().native_type();
     95   }
     96 
     97   // Called for each step of a scroll sequence initiated at the bottom right
     98   // corner of |window_|. Tests whether the resize shadow is shown.
     99   void ProcessBottomRightResizeGesture(ui::EventType type,
    100                                        const gfx::Vector2dF& delta) {
    101     if (type == ui::ET_GESTURE_SCROLL_END) {
    102       // After gesture scroll ends, there should be no resize shadow.
    103       EXPECT_FALSE(HasResizeShadow());
    104     } else {
    105       EXPECT_EQ(HTBOTTOMRIGHT, ResizeShadowHitTest());
    106     }
    107   }
    108 
    109   aura::Window* window() {
    110     return window_;
    111   }
    112 
    113  private:
    114   aura::Window* window_;
    115 
    116   DISALLOW_COPY_AND_ASSIGN(ResizeShadowAndCursorTest);
    117 };
    118 
    119 // Test whether the resize shadows are visible and the cursor type based on the
    120 // mouse's position.
    121 TEST_F(ResizeShadowAndCursorTest, MouseHover) {
    122   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    123   ASSERT_TRUE(ash::wm::GetWindowState(window())->IsNormalStateType());
    124 
    125   generator.MoveMouseTo(50, 50);
    126   EXPECT_FALSE(HasResizeShadow());
    127   EXPECT_EQ(ui::kCursorNull, GetCurrentCursorType());
    128 
    129   generator.MoveMouseTo(gfx::Point(50, 0));
    130   EXPECT_EQ(HTTOP, ResizeShadowHitTest());
    131   EXPECT_EQ(ui::kCursorNorthResize, GetCurrentCursorType());
    132 
    133   generator.MoveMouseTo(50, 50);
    134   EXPECT_FALSE(HasResizeShadow());
    135   EXPECT_EQ(ui::kCursorNull, GetCurrentCursorType());
    136 
    137   generator.MoveMouseTo(200, 100);
    138   EXPECT_EQ(HTBOTTOMRIGHT, ResizeShadowHitTest());
    139   EXPECT_EQ(ui::kCursorSouthEastResize, GetCurrentCursorType());
    140 
    141   generator.MoveMouseTo(50, 100);
    142   EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
    143   EXPECT_EQ(ui::kCursorSouthResize, GetCurrentCursorType());
    144 
    145   generator.MoveMouseTo(50, 100 + ash::kResizeOutsideBoundsSize - 1);
    146   EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
    147   EXPECT_EQ(ui::kCursorSouthResize, GetCurrentCursorType());
    148 
    149   generator.MoveMouseTo(50, 100 + ash::kResizeOutsideBoundsSize + 10);
    150   EXPECT_FALSE(HasResizeShadow());
    151   EXPECT_EQ(ui::kCursorNull, GetCurrentCursorType());
    152 
    153   generator.MoveMouseTo(50, 100 - ash::kResizeInsideBoundsSize);
    154   EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
    155   EXPECT_EQ(ui::kCursorSouthResize, GetCurrentCursorType());
    156 
    157   generator.MoveMouseTo(50, 100 - ash::kResizeInsideBoundsSize - 10);
    158   EXPECT_FALSE(HasResizeShadow());
    159   EXPECT_EQ(ui::kCursorNull, GetCurrentCursorType());
    160 }
    161 
    162 // Test that the resize shadows stay visible and that the cursor stays the same
    163 // as long as a user is resizing a window.
    164 TEST_F(ResizeShadowAndCursorTest, MouseDrag) {
    165   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    166   ASSERT_TRUE(ash::wm::GetWindowState(window())->IsNormalStateType());
    167   gfx::Size initial_size(window()->bounds().size());
    168 
    169   generator.MoveMouseTo(200, 50);
    170   generator.PressLeftButton();
    171   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    172   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    173 
    174   generator.MoveMouseTo(210, 50);
    175   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    176   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    177 
    178   generator.ReleaseLeftButton();
    179   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    180   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    181 
    182   gfx::Size new_size(window()->bounds().size());
    183   EXPECT_NE(new_size.ToString(), initial_size.ToString());
    184 }
    185 
    186 // Test that the resize shadows stay visible while resizing a window via touch.
    187 TEST_F(ResizeShadowAndCursorTest, Touch) {
    188   ASSERT_TRUE(ash::wm::GetWindowState(window())->IsNormalStateType());
    189   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    190 
    191   int start_x = 200 + ash::kResizeOutsideBoundsSize - 1;
    192   int start_y = 100 + ash::kResizeOutsideBoundsSize - 1;
    193   generator.GestureScrollSequenceWithCallback(
    194       gfx::Point(start_x, start_y),
    195       gfx::Point(start_x + 50, start_y + 50),
    196       base::TimeDelta::FromMilliseconds(200),
    197       3,
    198       base::Bind(&ResizeShadowAndCursorTest::ProcessBottomRightResizeGesture,
    199                  base::Unretained(this)));
    200 }
    201 
    202 // Test that the resize shadows are not visible and that the default cursor is
    203 // used when the window is maximized.
    204 TEST_F(ResizeShadowAndCursorTest, MaximizeRestore) {
    205   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    206   ASSERT_TRUE(ash::wm::GetWindowState(window())->IsNormalStateType());
    207 
    208   generator.MoveMouseTo(200, 50);
    209   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    210   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    211   generator.MoveMouseTo(200 - ash::kResizeInsideBoundsSize, 50);
    212   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    213   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    214 
    215   ash::wm::GetWindowState(window())->Maximize();
    216   gfx::Rect bounds(window()->GetBoundsInRootWindow());
    217   gfx::Point right_center(bounds.right() - 1,
    218                           (bounds.y() + bounds.bottom()) / 2);
    219   generator.MoveMouseTo(right_center);
    220   EXPECT_FALSE(HasResizeShadow());
    221   EXPECT_EQ(ui::kCursorNull, GetCurrentCursorType());
    222 
    223   ash::wm::GetWindowState(window())->Restore();
    224   generator.MoveMouseTo(200, 50);
    225   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    226   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    227   generator.MoveMouseTo(200 - ash::kResizeInsideBoundsSize, 50);
    228   EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
    229   EXPECT_EQ(ui::kCursorEastResize, GetCurrentCursorType());
    230 }
    231 
    232 }  // namespace test
    233 }  // namespace ash
    234