resize_shadow_and_cursor_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. #include "ash/frame/non_client_frame_view_ash.h"
  5. #include "ash/public/cpp/test/shell_test_api.h"
  6. #include "ash/public/cpp/window_properties.h"
  7. #include "ash/shell.h"
  8. #include "ash/test/ash_test_base.h"
  9. #include "ash/test/test_window_builder.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 "chromeos/ui/base/chromeos_ui_constants.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "ui/aura/window_event_dispatcher.h"
  17. #include "ui/base/cursor/cursor.h"
  18. #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
  19. #include "ui/base/hit_test.h"
  20. #include "ui/compositor/layer.h"
  21. #include "ui/events/test/event_generator.h"
  22. #include "ui/views/bubble/bubble_dialog_delegate_view.h"
  23. #include "ui/views/widget/widget.h"
  24. #include "ui/views/widget/widget_delegate.h"
  25. #include "ui/wm/core/cursor_manager.h"
  26. using chromeos::kResizeInsideBoundsSize;
  27. using chromeos::kResizeOutsideBoundsSize;
  28. namespace ash {
  29. namespace {
  30. // views::WidgetDelegate which uses ash::NonClientFrameViewAsh.
  31. class TestWidgetDelegate : public views::WidgetDelegateView {
  32. public:
  33. TestWidgetDelegate() {
  34. SetCanMaximize(true);
  35. SetCanMinimize(true);
  36. SetCanResize(true);
  37. }
  38. TestWidgetDelegate(const TestWidgetDelegate&) = delete;
  39. TestWidgetDelegate& operator=(const TestWidgetDelegate&) = delete;
  40. ~TestWidgetDelegate() override = default;
  41. // views::WidgetDelegateView overrides:
  42. std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
  43. views::Widget* widget) override {
  44. return std::make_unique<NonClientFrameViewAsh>(widget);
  45. }
  46. };
  47. } // namespace
  48. // The test tests that the mouse cursor is changed and that the resize shadows
  49. // are shown when the mouse is hovered over the window edge.
  50. class ResizeShadowAndCursorTest : public AshTestBase {
  51. public:
  52. ResizeShadowAndCursorTest() = default;
  53. ResizeShadowAndCursorTest(const ResizeShadowAndCursorTest&) = delete;
  54. ResizeShadowAndCursorTest& operator=(const ResizeShadowAndCursorTest&) =
  55. delete;
  56. ~ResizeShadowAndCursorTest() override = default;
  57. // AshTestBase override:
  58. void SetUp() override {
  59. AshTestBase::SetUp();
  60. views::Widget* widget = views::Widget::CreateWindowWithContext(
  61. new TestWidgetDelegate(), GetContext(), gfx::Rect(0, 0, 200, 100));
  62. widget->Show();
  63. window_ = widget->GetNativeView();
  64. // Add a child window to |window_| in order to properly test that the resize
  65. // handles and the resize shadows are shown when the mouse is
  66. // ash::kResizeInsideBoundsSize inside of |window_|'s edges.
  67. aura::Window* child = TestWindowBuilder()
  68. .SetColorWindowDelegate(SK_ColorWHITE)
  69. .SetBounds(gfx::Rect(0, 10, 200, 90))
  70. .Build()
  71. .release();
  72. window_->AddChild(child);
  73. }
  74. const ResizeShadow* GetShadow() const {
  75. return Shell::Get()->resize_shadow_controller()->GetShadowForWindowForTest(
  76. window_);
  77. }
  78. // Returns the hit test code if there is a resize shadow. Returns HTNOWHERE if
  79. // there is no resize shadow.
  80. int ResizeShadowHitTest() const {
  81. auto* resize_shadow = GetShadow();
  82. return resize_shadow ? resize_shadow->GetLastHitTestForTest() : HTNOWHERE;
  83. }
  84. // Returns true if there is a resize shadow with a given type. Default type is
  85. // unlock for compatibility.
  86. void VerifyResizeShadow(bool visible) const {
  87. if (visible)
  88. EXPECT_TRUE(GetShadow());
  89. if (GetShadow()) {
  90. const ui::Layer* shadow_layer = GetShadow()->GetLayerForTest();
  91. EXPECT_EQ(visible, shadow_layer->GetTargetVisibility());
  92. ASSERT_TRUE(window_->layer());
  93. EXPECT_EQ(window_->layer()->parent(), shadow_layer->parent());
  94. const auto& layers = shadow_layer->parent()->children();
  95. // We don't care about the layer order if it's invisible.
  96. if (visible) {
  97. // Make sure the shadow layer is stacked directly beneath the window
  98. // layer.
  99. EXPECT_EQ(*(std::find(layers.begin(), layers.end(), shadow_layer) + 1),
  100. window_->layer());
  101. }
  102. }
  103. }
  104. // Returns the current cursor type.
  105. ui::mojom::CursorType GetCurrentCursorType() const {
  106. return Shell::Get()->cursor_manager()->GetCursor().type();
  107. }
  108. // Called for each step of a scroll sequence initiated at the bottom right
  109. // corner of |window_|. Tests whether the resize shadow is shown.
  110. void ProcessBottomRightResizeGesture(ui::EventType type,
  111. const gfx::Vector2dF& delta) {
  112. if (type == ui::ET_GESTURE_SCROLL_END) {
  113. // After gesture scroll ends, there should be no resize shadow.
  114. VerifyResizeShadow(false);
  115. } else {
  116. VerifyResizeShadow(true);
  117. EXPECT_EQ(HTBOTTOMRIGHT, ResizeShadowHitTest());
  118. }
  119. }
  120. aura::Window* window() { return window_; }
  121. private:
  122. aura::Window* window_;
  123. };
  124. // Test whether the resize shadows are visible and the cursor type based on the
  125. // mouse's position.
  126. TEST_F(ResizeShadowAndCursorTest, MouseHover) {
  127. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  128. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  129. generator.MoveMouseTo(50, 50);
  130. VerifyResizeShadow(false);
  131. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  132. generator.MoveMouseTo(gfx::Point(50, 0));
  133. VerifyResizeShadow(true);
  134. EXPECT_EQ(HTTOP, ResizeShadowHitTest());
  135. EXPECT_EQ(ui::mojom::CursorType::kNorthResize, GetCurrentCursorType());
  136. generator.MoveMouseTo(50, 50);
  137. VerifyResizeShadow(false);
  138. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  139. generator.MoveMouseTo(200, 100);
  140. VerifyResizeShadow(true);
  141. EXPECT_EQ(HTBOTTOMRIGHT, ResizeShadowHitTest());
  142. EXPECT_EQ(ui::mojom::CursorType::kSouthEastResize, GetCurrentCursorType());
  143. generator.MoveMouseTo(50, 100);
  144. VerifyResizeShadow(true);
  145. EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
  146. EXPECT_EQ(ui::mojom::CursorType::kSouthResize, GetCurrentCursorType());
  147. generator.MoveMouseTo(50, 100 + kResizeOutsideBoundsSize - 1);
  148. VerifyResizeShadow(true);
  149. EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
  150. EXPECT_EQ(ui::mojom::CursorType::kSouthResize, GetCurrentCursorType());
  151. generator.MoveMouseTo(50, 100 + kResizeOutsideBoundsSize + 10);
  152. VerifyResizeShadow(false);
  153. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  154. generator.MoveMouseTo(50, 100 - kResizeInsideBoundsSize);
  155. VerifyResizeShadow(true);
  156. EXPECT_EQ(HTBOTTOM, ResizeShadowHitTest());
  157. EXPECT_EQ(ui::mojom::CursorType::kSouthResize, GetCurrentCursorType());
  158. generator.MoveMouseTo(50, 100 - kResizeInsideBoundsSize - 10);
  159. VerifyResizeShadow(false);
  160. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  161. }
  162. // For windows that are not resizable, checks that there is no resize shadow,
  163. // and for the correct cursor type for the cursor position.
  164. TEST_F(ResizeShadowAndCursorTest, MouseHoverOverNonresizable) {
  165. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  166. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  167. // Make the window nonresizable.
  168. auto* const widget = views::Widget::GetWidgetForNativeWindow(window());
  169. auto* widget_delegate = widget->widget_delegate();
  170. widget_delegate->SetCanResize(false);
  171. generator.MoveMouseTo(gfx::Point(50, 50));
  172. VerifyResizeShadow(false);
  173. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  174. generator.MoveMouseTo(gfx::Point(50, 0));
  175. VerifyResizeShadow(false);
  176. EXPECT_EQ(ui::mojom::CursorType::kNorthSouthNoResize, GetCurrentCursorType());
  177. generator.MoveMouseTo(gfx::Point(50, 50));
  178. VerifyResizeShadow(false);
  179. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  180. generator.MoveMouseTo(gfx::Point(199, 99));
  181. VerifyResizeShadow(false);
  182. EXPECT_EQ(ui::mojom::CursorType::kNorthWestSouthEastNoResize,
  183. GetCurrentCursorType());
  184. generator.MoveMouseTo(gfx::Point(50, 99));
  185. VerifyResizeShadow(false);
  186. EXPECT_EQ(ui::mojom::CursorType::kNorthSouthNoResize, GetCurrentCursorType());
  187. generator.MoveMouseTo(gfx::Point(50, 100 + kResizeOutsideBoundsSize - 1));
  188. VerifyResizeShadow(false);
  189. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  190. generator.MoveMouseTo(gfx::Point(50, 100 + kResizeOutsideBoundsSize + 10));
  191. VerifyResizeShadow(false);
  192. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  193. generator.MoveMouseTo(gfx::Point(50, 100 - kResizeInsideBoundsSize));
  194. VerifyResizeShadow(false);
  195. EXPECT_EQ(ui::mojom::CursorType::kNorthSouthNoResize, GetCurrentCursorType());
  196. generator.MoveMouseTo(gfx::Point(50, 100 - kResizeInsideBoundsSize - 10));
  197. VerifyResizeShadow(false);
  198. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  199. }
  200. TEST_F(ResizeShadowAndCursorTest, DefaultCursorOnBubbleWidgetCorners) {
  201. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  202. // Create a dummy view for the bubble, adding it to the window.
  203. views::View* child_view = new views::View();
  204. child_view->SetBounds(200, 200, 10, 10);
  205. views::Widget::GetWidgetForNativeWindow(window())
  206. ->GetRootView()
  207. ->AddChildView(child_view);
  208. // Create the bubble widget.
  209. views::Widget* bubble(views::BubbleDialogDelegateView::CreateBubble(
  210. new views::BubbleDialogDelegateView(child_view,
  211. views::BubbleBorder::NONE)));
  212. bubble->Show();
  213. // Get the screen rectangle for the bubble frame
  214. const gfx::Rect bounds = bubble->GetNativeView()->GetBoundsInScreen();
  215. EXPECT_THAT(
  216. bounds,
  217. ::testing::AllOf(::testing::Property(&gfx::Rect::x, ::testing::Gt(0)),
  218. ::testing::Property(&gfx::Rect::y, ::testing::Gt(0))));
  219. // The cursor at the frame corners should be the default cursor.
  220. generator.MoveMouseTo(bounds.origin());
  221. EXPECT_THAT(GetCurrentCursorType(),
  222. ::testing::Eq(ui::mojom::CursorType::kNull));
  223. generator.MoveMouseTo(bounds.top_right());
  224. EXPECT_THAT(GetCurrentCursorType(),
  225. ::testing::Eq(ui::mojom::CursorType::kNull));
  226. generator.MoveMouseTo(bounds.bottom_left());
  227. EXPECT_THAT(GetCurrentCursorType(),
  228. ::testing::Eq(ui::mojom::CursorType::kNull));
  229. generator.MoveMouseTo(bounds.bottom_right());
  230. EXPECT_THAT(GetCurrentCursorType(),
  231. ::testing::Eq(ui::mojom::CursorType::kNull));
  232. }
  233. TEST_F(ResizeShadowAndCursorTest, NoResizeShadowOnNonToplevelWindow) {
  234. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  235. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  236. auto* embedded = views::Widget::CreateWindowWithContext(
  237. new TestWidgetDelegate(), GetContext(), gfx::Rect(0, 0, 100, 100));
  238. embedded->Show();
  239. window()->AddChild(embedded->GetNativeWindow());
  240. embedded->GetNativeWindow()->SetName("BBB");
  241. window()->SetName("AAAA");
  242. embedded->SetBounds(gfx::Rect(10, 10, 100, 100));
  243. generator.MoveMouseTo(50, 11);
  244. VerifyResizeShadow(false);
  245. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  246. EXPECT_FALSE(
  247. Shell::Get()->resize_shadow_controller()->GetShadowForWindowForTest(
  248. embedded->GetNativeWindow()));
  249. generator.MoveMouseTo(gfx::Point(50, 0));
  250. VerifyResizeShadow(true);
  251. EXPECT_EQ(HTTOP, ResizeShadowHitTest());
  252. EXPECT_EQ(ui::mojom::CursorType::kNorthResize, GetCurrentCursorType());
  253. EXPECT_FALSE(
  254. Shell::Get()->resize_shadow_controller()->GetShadowForWindowForTest(
  255. embedded->GetNativeWindow()));
  256. }
  257. // Test that the resize shadows stay visible and that the cursor stays the same
  258. // as long as a user is resizing a window.
  259. TEST_F(ResizeShadowAndCursorTest, MouseDrag) {
  260. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  261. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  262. gfx::Size initial_size(window()->bounds().size());
  263. generator.MoveMouseTo(200, 50);
  264. generator.PressLeftButton();
  265. VerifyResizeShadow(true);
  266. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  267. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  268. generator.MoveMouseTo(210, 50);
  269. VerifyResizeShadow(true);
  270. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  271. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  272. generator.ReleaseLeftButton();
  273. VerifyResizeShadow(true);
  274. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  275. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  276. gfx::Size new_size(window()->bounds().size());
  277. EXPECT_NE(new_size.ToString(), initial_size.ToString());
  278. }
  279. // Test that the resize shadows stay visible while resizing a window via touch.
  280. TEST_F(ResizeShadowAndCursorTest, Touch) {
  281. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  282. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  283. int start_x = 200 + kResizeOutsideBoundsSize - 1;
  284. int start_y = 100 + kResizeOutsideBoundsSize - 1;
  285. generator.GestureScrollSequenceWithCallback(
  286. gfx::Point(start_x, start_y), gfx::Point(start_x + 50, start_y + 50),
  287. base::Milliseconds(200), 3,
  288. base::BindRepeating(
  289. &ResizeShadowAndCursorTest::ProcessBottomRightResizeGesture,
  290. base::Unretained(this)));
  291. }
  292. // Test that the resize shadows are not visible and that the default cursor is
  293. // used when the window is maximized.
  294. TEST_F(ResizeShadowAndCursorTest, MaximizeRestore) {
  295. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  296. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  297. generator.MoveMouseTo(200, 50);
  298. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  299. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  300. generator.MoveMouseTo(200 - kResizeInsideBoundsSize, 50);
  301. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  302. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  303. WindowState::Get(window())->Maximize();
  304. gfx::Rect bounds(window()->GetBoundsInRootWindow());
  305. gfx::Point right_center(bounds.right() - 1,
  306. (bounds.y() + bounds.bottom()) / 2);
  307. generator.MoveMouseTo(right_center);
  308. VerifyResizeShadow(false);
  309. EXPECT_EQ(ui::mojom::CursorType::kNull, GetCurrentCursorType());
  310. WindowState::Get(window())->Restore();
  311. generator.MoveMouseTo(200, 50);
  312. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  313. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  314. generator.MoveMouseTo(200 - kResizeInsideBoundsSize, 50);
  315. EXPECT_EQ(HTRIGHT, ResizeShadowHitTest());
  316. EXPECT_EQ(ui::mojom::CursorType::kEastResize, GetCurrentCursorType());
  317. }
  318. // Verifies that the shadow hides when a window is minimized. Regression test
  319. // for crbug.com/752583
  320. TEST_F(ResizeShadowAndCursorTest, Minimize) {
  321. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  322. ASSERT_TRUE(WindowState::Get(window())->IsNormalStateType());
  323. generator.MoveMouseTo(200, 50);
  324. VerifyResizeShadow(true);
  325. WindowState::Get(window())->Minimize();
  326. VerifyResizeShadow(false);
  327. WindowState::Get(window())->Restore();
  328. VerifyResizeShadow(false);
  329. }
  330. // Verifies that the lock style shadow gets updated when the window's bounds
  331. // changed.
  332. TEST_F(ResizeShadowAndCursorTest, LockShadowBounds) {
  333. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  334. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  335. // Set window's bounds
  336. const gfx::Rect kOldBounds(20, 30, 400, 300);
  337. window()->SetBounds(kOldBounds);
  338. auto* resize_shadow = GetShadow();
  339. ASSERT_TRUE(resize_shadow);
  340. VerifyResizeShadow(true);
  341. auto* layer = resize_shadow->GetLayerForTest();
  342. constexpr int kVisualThickness = 6;
  343. EXPECT_EQ(gfx::Rect(kOldBounds.width() + kVisualThickness * 2,
  344. kOldBounds.height() + kVisualThickness * 2)
  345. .ToString(),
  346. gfx::Rect(layer->GetTargetBounds().size()).ToString());
  347. // Change the window's bounds, the shadow's should be updated too.
  348. gfx::Rect kNewBounds(50, 60, 500, 400);
  349. window()->SetBounds(kNewBounds);
  350. EXPECT_EQ(gfx::Rect(kNewBounds.width() + kVisualThickness * 2,
  351. kNewBounds.height() + kVisualThickness * 2)
  352. .ToString(),
  353. gfx::Rect(layer->GetTargetBounds().size()).ToString());
  354. }
  355. // Tests that shadow gets updated according to the window's visibility.
  356. TEST_F(ResizeShadowAndCursorTest, ShowHideLockShadow) {
  357. ASSERT_FALSE(GetShadow());
  358. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  359. // Test shown window.
  360. window()->Show();
  361. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  362. ASSERT_TRUE(GetShadow());
  363. VerifyResizeShadow(true);
  364. Shell::Get()->resize_shadow_controller()->HideShadow(window());
  365. VerifyResizeShadow(false);
  366. Shell::Get()->resize_shadow_controller()->TryShowAllShadows();
  367. VerifyResizeShadow(true);
  368. Shell::Get()->resize_shadow_controller()->HideAllShadows();
  369. VerifyResizeShadow(false);
  370. // Test hidden window.
  371. window()->Hide();
  372. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  373. VerifyResizeShadow(false);
  374. Shell::Get()->resize_shadow_controller()->HideShadow(window());
  375. VerifyResizeShadow(false);
  376. Shell::Get()->resize_shadow_controller()->TryShowAllShadows();
  377. VerifyResizeShadow(false);
  378. Shell::Get()->resize_shadow_controller()->HideAllShadows();
  379. VerifyResizeShadow(false);
  380. }
  381. // Tests that shadow gets updated when the window's visibility changed.
  382. TEST_F(ResizeShadowAndCursorTest, WindowVisibilityChange) {
  383. ASSERT_FALSE(GetShadow());
  384. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  385. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  386. ASSERT_TRUE(GetShadow());
  387. window()->Show();
  388. VerifyResizeShadow(true);
  389. window()->Hide();
  390. VerifyResizeShadow(false);
  391. window()->Show();
  392. VerifyResizeShadow(true);
  393. }
  394. // Tests that shadow type gets updated according to the window's property.
  395. TEST_F(ResizeShadowAndCursorTest, ResizeShadowTypeChange) {
  396. ASSERT_FALSE(GetShadow());
  397. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  398. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  399. ASSERT_TRUE(GetShadow());
  400. ASSERT_EQ(GetShadow()->GetResizeShadowTypeForTest(), ResizeShadowType::kLock);
  401. Shell::Get()->resize_shadow_controller()->HideShadow(window());
  402. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kUnlock);
  403. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  404. ASSERT_EQ(GetShadow()->GetResizeShadowTypeForTest(),
  405. ResizeShadowType::kUnlock);
  406. Shell::Get()->resize_shadow_controller()->HideShadow(window());
  407. }
  408. // Tests that shadow gets updated when the window's state changed.
  409. TEST_F(ResizeShadowAndCursorTest, WindowStateChange) {
  410. ASSERT_FALSE(GetShadow());
  411. auto* const window_state = WindowState::Get(window());
  412. ASSERT_TRUE(window_state->IsNormalStateType());
  413. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  414. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  415. VerifyResizeShadow(true);
  416. window_state->Maximize();
  417. VerifyResizeShadow(false);
  418. window_state->Restore();
  419. VerifyResizeShadow(true);
  420. window_state->Minimize();
  421. VerifyResizeShadow(false);
  422. window_state->Unminimize();
  423. VerifyResizeShadow(true);
  424. }
  425. // Tests that shadow gets hidden and restored according to the oveview mode
  426. // state.
  427. TEST_F(ResizeShadowAndCursorTest, OverviewModeChange) {
  428. ASSERT_FALSE(GetShadow());
  429. window()->SetProperty(kResizeShadowTypeKey, ResizeShadowType::kLock);
  430. // Requests ShowShadow() before entering overview.
  431. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  432. ASSERT_TRUE(GetShadow());
  433. window()->Show();
  434. VerifyResizeShadow(true);
  435. EnterOverview();
  436. VerifyResizeShadow(false);
  437. ExitOverview();
  438. VerifyResizeShadow(true);
  439. Shell::Get()->resize_shadow_controller()->HideAllShadows();
  440. // Requests ShowShadow() after entering overview.
  441. EnterOverview();
  442. Shell::Get()->resize_shadow_controller()->ShowShadow(window());
  443. VerifyResizeShadow(false);
  444. ExitOverview();
  445. VerifyResizeShadow(true);
  446. }
  447. } // namespace ash