window_modality_controller_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  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. #include "ui/wm/core/window_modality_controller.h"
  5. #include "ash/shell.h"
  6. #include "ash/test/ash_test_base.h"
  7. #include "ash/wm/test_child_modal_parent.h"
  8. #include "ash/wm/window_util.h"
  9. #include "ui/aura/client/aura_constants.h"
  10. #include "ui/aura/client/capture_client.h"
  11. #include "ui/aura/test/test_window_delegate.h"
  12. #include "ui/aura/test/test_windows.h"
  13. #include "ui/aura/window.h"
  14. #include "ui/aura/window_event_dispatcher.h"
  15. #include "ui/base/ui_base_types.h"
  16. #include "ui/events/test/event_generator.h"
  17. #include "ui/views/test/capture_tracking_view.h"
  18. #include "ui/views/widget/widget.h"
  19. #include "ui/wm/core/window_util.h"
  20. namespace ash {
  21. using WindowModalityControllerTest = AshTestBase;
  22. namespace {
  23. bool ValidateStacking(aura::Window* parent, int ids[], int count) {
  24. for (int i = 0; i < count; ++i) {
  25. if (parent->children().at(i)->GetId() != ids[i])
  26. return false;
  27. }
  28. return true;
  29. }
  30. } // namespace
  31. // Creates three windows, w1, w11, and w12. w11 is a non-modal transient, w12 is
  32. // a modal transient.
  33. // Validates:
  34. // - it should be possible to activate w12 even when w11 is open.
  35. // - activating w1 activates w12 and updates stacking order appropriately.
  36. // - closing a window passes focus up the stack.
  37. TEST_F(WindowModalityControllerTest, BasicActivation) {
  38. aura::test::TestWindowDelegate d;
  39. std::unique_ptr<aura::Window> w1(
  40. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  41. std::unique_ptr<aura::Window> w11(
  42. CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
  43. std::unique_ptr<aura::Window> w12(
  44. CreateTestWindowInShellWithDelegate(&d, -12, gfx::Rect()));
  45. ::wm::AddTransientChild(w1.get(), w11.get());
  46. wm::ActivateWindow(w1.get());
  47. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  48. wm::ActivateWindow(w11.get());
  49. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  50. w12->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  51. ::wm::AddTransientChild(w1.get(), w12.get());
  52. wm::ActivateWindow(w12.get());
  53. EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
  54. wm::ActivateWindow(w11.get());
  55. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  56. int check1[] = {-1, -12, -11};
  57. EXPECT_TRUE(ValidateStacking(w1->parent(), check1, std::size(check1)));
  58. wm::ActivateWindow(w1.get());
  59. EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
  60. // Transient children are always stacked above their transient parent, which
  61. // is why this order is not -11, -1, -12.
  62. int check2[] = {-1, -11, -12};
  63. EXPECT_TRUE(ValidateStacking(w1->parent(), check2, std::size(check2)));
  64. w12.reset();
  65. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  66. w11.reset();
  67. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  68. }
  69. // Create two toplevel windows w1 and w2, and nest two modals w11 and w111 below
  70. // w1.
  71. // Validates:
  72. // - activating w1 while w11/w111 is showing always activates most deeply nested
  73. // descendant.
  74. // - closing a window passes focus up the stack.
  75. TEST_F(WindowModalityControllerTest, NestedModals) {
  76. aura::test::TestWindowDelegate d;
  77. std::unique_ptr<aura::Window> w1(
  78. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  79. std::unique_ptr<aura::Window> w11(
  80. CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
  81. std::unique_ptr<aura::Window> w111(
  82. CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect()));
  83. std::unique_ptr<aura::Window> w2(
  84. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  85. ::wm::AddTransientChild(w1.get(), w11.get());
  86. ::wm::AddTransientChild(w11.get(), w111.get());
  87. wm::ActivateWindow(w1.get());
  88. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  89. wm::ActivateWindow(w2.get());
  90. EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
  91. // Set up modality.
  92. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  93. w111->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  94. wm::ActivateWindow(w1.get());
  95. EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
  96. int check1[] = {-2, -1, -11, -111};
  97. EXPECT_TRUE(ValidateStacking(w1->parent(), check1, std::size(check1)));
  98. wm::ActivateWindow(w11.get());
  99. EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
  100. EXPECT_TRUE(ValidateStacking(w1->parent(), check1, std::size(check1)));
  101. wm::ActivateWindow(w111.get());
  102. EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
  103. EXPECT_TRUE(ValidateStacking(w1->parent(), check1, std::size(check1)));
  104. wm::ActivateWindow(w2.get());
  105. EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
  106. int check2[] = {-1, -11, -111, -2};
  107. EXPECT_TRUE(ValidateStacking(w1->parent(), check2, std::size(check2)));
  108. w2.reset();
  109. EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
  110. w111.reset();
  111. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  112. w11.reset();
  113. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  114. }
  115. // Create two toplevel windows w1 and w2, and nest two modals w11 and w111 below
  116. // w1.
  117. // Validates:
  118. // - destroying w11 while w111 is focused activates w1.
  119. TEST_F(WindowModalityControllerTest, NestedModalsOuterClosed) {
  120. aura::test::TestWindowDelegate d;
  121. std::unique_ptr<aura::Window> w1(
  122. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  123. std::unique_ptr<aura::Window> w11(
  124. CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
  125. // |w111| will be owned and deleted by |w11|.
  126. aura::Window* w111 =
  127. CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect());
  128. std::unique_ptr<aura::Window> w2(
  129. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  130. ::wm::AddTransientChild(w1.get(), w11.get());
  131. ::wm::AddTransientChild(w11.get(), w111);
  132. wm::ActivateWindow(w1.get());
  133. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  134. wm::ActivateWindow(w2.get());
  135. EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
  136. // Set up modality.
  137. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  138. w111->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  139. wm::ActivateWindow(w1.get());
  140. EXPECT_TRUE(wm::IsActiveWindow(w111));
  141. w111->Hide();
  142. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  143. // TODO(oshima): Re-showing doesn't set the focus back to
  144. // modal window. There is no such use case right now, but it
  145. // probably should.
  146. w11.reset();
  147. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  148. }
  149. // Modality also prevents events from being passed to the transient parent.
  150. TEST_F(WindowModalityControllerTest, Events) {
  151. aura::test::TestWindowDelegate d;
  152. std::unique_ptr<aura::Window> w1(
  153. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect(0, 0, 100, 100)));
  154. std::unique_ptr<aura::Window> w11(
  155. CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect(20, 20, 50, 50)));
  156. std::unique_ptr<aura::Window> w111(
  157. CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect(20, 20, 50, 50)));
  158. ::wm::AddTransientChild(w1.get(), w11.get());
  159. // Add a non-modal child to the modal window in order to ensure modality still
  160. // works in this case. This is a regression test for https://crbug.com/456697.
  161. ::wm::AddTransientChild(w11.get(), w111.get());
  162. {
  163. // Clicking a point within w1 should activate that window.
  164. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  165. gfx::Point(10, 10));
  166. generator.ClickLeftButton();
  167. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  168. }
  169. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  170. {
  171. // Clicking a point within w1 should activate w11.
  172. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  173. gfx::Point(10, 10));
  174. generator.ClickLeftButton();
  175. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  176. }
  177. }
  178. // Events on modal parent activate.
  179. TEST_F(WindowModalityControllerTest, EventsForEclipsedWindows) {
  180. aura::test::TestWindowDelegate d;
  181. std::unique_ptr<aura::Window> w1(
  182. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect(0, 0, 100, 100)));
  183. std::unique_ptr<aura::Window> w11(
  184. CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect(20, 20, 50, 50)));
  185. ::wm::AddTransientChild(w1.get(), w11.get());
  186. std::unique_ptr<aura::Window> w2(
  187. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect(0, 0, 50, 50)));
  188. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  189. // Partially eclipse w1 with w2.
  190. wm::ActivateWindow(w2.get());
  191. {
  192. // Clicking a point on w1 that is not eclipsed by w2.
  193. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  194. gfx::Point(90, 90));
  195. generator.ClickLeftButton();
  196. EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
  197. }
  198. }
  199. // Creates windows w1 and non activatiable child w11. Creates transient window
  200. // w2 and adds it as a transeint child of w1. Ensures that w2 is parented to
  201. // the parent of w1, and that GetModalTransient(w11) returns w2.
  202. TEST_F(WindowModalityControllerTest, GetModalTransient) {
  203. aura::test::TestWindowDelegate d;
  204. std::unique_ptr<aura::Window> w1(
  205. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  206. std::unique_ptr<aura::Window> w11(
  207. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
  208. std::unique_ptr<aura::Window> w2(
  209. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  210. w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  211. aura::Window* wt;
  212. wt = ::wm::GetModalTransient(w1.get());
  213. ASSERT_EQ(nullptr, wt);
  214. // Parent w2 to w1. It should get parented to the parent of w1.
  215. ::wm::AddTransientChild(w1.get(), w2.get());
  216. ASSERT_EQ(2U, w1->parent()->children().size());
  217. EXPECT_EQ(-2, w1->parent()->children().at(1)->GetId());
  218. // Request the modal transient window for w1, it should be w2.
  219. wt = ::wm::GetModalTransient(w1.get());
  220. ASSERT_NE(nullptr, wt);
  221. EXPECT_EQ(-2, wt->GetId());
  222. // Request the modal transient window for w11, it should also be w2.
  223. wt = ::wm::GetModalTransient(w11.get());
  224. ASSERT_NE(nullptr, wt);
  225. EXPECT_EQ(-2, wt->GetId());
  226. }
  227. // Verifies we generate a capture lost when showing a modal window.
  228. TEST_F(WindowModalityControllerTest, ChangeCapture) {
  229. views::Widget* widget = views::Widget::CreateWindowWithContext(
  230. nullptr, Shell::GetPrimaryRootWindow(), gfx::Rect(0, 0, 200, 200));
  231. std::unique_ptr<aura::Window> widget_window(widget->GetNativeView());
  232. views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView;
  233. widget->client_view()->AddChildView(view);
  234. view->SetBoundsRect(widget->client_view()->GetLocalBounds());
  235. widget->Show();
  236. gfx::Point center(view->width() / 2, view->height() / 2);
  237. views::View::ConvertPointToScreen(view, &center);
  238. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), center);
  239. generator.PressLeftButton();
  240. EXPECT_TRUE(view->got_press());
  241. views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
  242. nullptr, widget->GetNativeView(), gfx::Rect(50, 50, 200, 200));
  243. std::unique_ptr<aura::Window> modal_window(modal_widget->GetNativeView());
  244. modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  245. views::test::CaptureTrackingView* modal_view =
  246. new views::test::CaptureTrackingView;
  247. modal_widget->client_view()->AddChildView(modal_view);
  248. modal_view->SetBoundsRect(modal_widget->client_view()->GetLocalBounds());
  249. modal_widget->Show();
  250. EXPECT_TRUE(view->got_capture_lost());
  251. generator.ReleaseLeftButton();
  252. view->reset();
  253. EXPECT_FALSE(modal_view->got_capture_lost());
  254. EXPECT_FALSE(modal_view->got_press());
  255. gfx::Point modal_center(modal_view->width() / 2, modal_view->height() / 2);
  256. views::View::ConvertPointToScreen(modal_view, &modal_center);
  257. generator.MoveMouseTo(modal_center, 1);
  258. generator.PressLeftButton();
  259. EXPECT_TRUE(modal_view->got_press());
  260. EXPECT_FALSE(modal_view->got_capture_lost());
  261. EXPECT_FALSE(view->got_capture_lost());
  262. EXPECT_FALSE(view->got_press());
  263. }
  264. // Test that when a child modal window becomes visible, we only release the
  265. // capture window if the current capture window is in the hierarchy of the child
  266. // modal window's modal parent window.
  267. TEST_F(WindowModalityControllerTest, ReleaseCapture) {
  268. // Create a window hierarchy like this:
  269. // _______________w0______________
  270. // | | |
  271. // w1 <------ w3 w2
  272. // | (modal to)
  273. // w11
  274. aura::test::TestWindowDelegate d;
  275. std::unique_ptr<aura::Window> w1(
  276. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  277. std::unique_ptr<aura::Window> w11(
  278. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
  279. std::unique_ptr<aura::Window> w2(
  280. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  281. std::unique_ptr<aura::Window> w3(
  282. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  283. w3->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
  284. ::wm::SetModalParent(w3.get(), w1.get());
  285. // w1's capture should be released when w3 becomes visible.
  286. w3->Hide();
  287. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  288. ->SetCapture(w1.get());
  289. EXPECT_EQ(w1.get(),
  290. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  291. ->GetGlobalCaptureWindow());
  292. w3->Show();
  293. EXPECT_NE(w1.get(),
  294. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  295. ->GetGlobalCaptureWindow());
  296. // w11's capture should be released when w3 becomes visible.
  297. w3->Hide();
  298. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  299. ->SetCapture(w11.get());
  300. EXPECT_EQ(w11.get(),
  301. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  302. ->GetGlobalCaptureWindow());
  303. w3->Show();
  304. EXPECT_NE(w11.get(),
  305. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  306. ->GetGlobalCaptureWindow());
  307. // w2's capture should not be released when w3 becomes visible.
  308. w3->Hide();
  309. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  310. ->SetCapture(w2.get());
  311. EXPECT_EQ(w2.get(),
  312. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  313. ->GetGlobalCaptureWindow());
  314. w3->Show();
  315. EXPECT_EQ(w2.get(),
  316. aura::client::GetCaptureClient(Shell::GetPrimaryRootWindow())
  317. ->GetGlobalCaptureWindow());
  318. }
  319. class TouchTrackerWindowDelegate : public aura::test::TestWindowDelegate {
  320. public:
  321. TouchTrackerWindowDelegate()
  322. : received_touch_(false), last_event_type_(ui::ET_UNKNOWN) {}
  323. TouchTrackerWindowDelegate(const TouchTrackerWindowDelegate&) = delete;
  324. TouchTrackerWindowDelegate& operator=(const TouchTrackerWindowDelegate&) =
  325. delete;
  326. ~TouchTrackerWindowDelegate() override = default;
  327. void reset() {
  328. received_touch_ = false;
  329. last_event_type_ = ui::ET_UNKNOWN;
  330. }
  331. bool received_touch() const { return received_touch_; }
  332. ui::EventType last_event_type() const { return last_event_type_; }
  333. private:
  334. // Overridden from aura::test::TestWindowDelegate.
  335. void OnTouchEvent(ui::TouchEvent* event) override {
  336. received_touch_ = true;
  337. last_event_type_ = event->type();
  338. aura::test::TestWindowDelegate::OnTouchEvent(event);
  339. }
  340. bool received_touch_;
  341. ui::EventType last_event_type_;
  342. };
  343. // Modality should prevent events from being passed to transient window tree
  344. // rooted to the top level window.
  345. TEST_F(WindowModalityControllerTest, TouchEvent) {
  346. TouchTrackerWindowDelegate d1;
  347. std::unique_ptr<aura::Window> w1(
  348. CreateTestWindowInShellWithDelegate(&d1, -1, gfx::Rect(0, 0, 100, 100)));
  349. TouchTrackerWindowDelegate d11;
  350. std::unique_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(
  351. &d11, -11, gfx::Rect(20, 20, 20, 20)));
  352. TouchTrackerWindowDelegate d12;
  353. std::unique_ptr<aura::Window> w12(CreateTestWindowInShellWithDelegate(
  354. &d12, -12, gfx::Rect(40, 20, 20, 20)));
  355. TouchTrackerWindowDelegate d2;
  356. std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate(
  357. &d2, -2, gfx::Rect(100, 0, 100, 100)));
  358. // Make |w11| and |w12| non-resizable to avoid touch events inside its
  359. // transient parent |w1| from going to them because of
  360. // EasyResizeWindowTargeter.
  361. w11->SetProperty(aura::client::kResizeBehaviorKey,
  362. aura::client::kResizeBehaviorCanMaximize |
  363. aura::client::kResizeBehaviorCanMinimize);
  364. w12->SetProperty(aura::client::kResizeBehaviorKey,
  365. aura::client::kResizeBehaviorCanMaximize |
  366. aura::client::kResizeBehaviorCanMinimize);
  367. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  368. gfx::Point(10, 10));
  369. ::wm::AddTransientChild(w1.get(), w11.get());
  370. ::wm::AddTransientChild(w1.get(), w12.get());
  371. d1.reset();
  372. d11.reset();
  373. d12.reset();
  374. d2.reset();
  375. {
  376. // Adding a modal window while a touch is down in top level transient window
  377. // should fire a touch cancel.
  378. generator.PressTouch();
  379. generator.MoveTouch(gfx::Point(10, 15));
  380. EXPECT_TRUE(d1.received_touch());
  381. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  382. d1.reset();
  383. d11.reset();
  384. d12.reset();
  385. d2.reset();
  386. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  387. EXPECT_TRUE(d1.received_touch());
  388. EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d1.last_event_type());
  389. EXPECT_FALSE(d11.received_touch());
  390. EXPECT_FALSE(d12.received_touch());
  391. EXPECT_FALSE(d2.received_touch());
  392. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
  393. }
  394. {
  395. // Adding a modal window while a touch is down in window tree rooted to top
  396. // level transient window should fire a touch cancel.
  397. generator.MoveTouch(gfx::Point(50, 30));
  398. generator.PressTouch();
  399. generator.MoveTouch(gfx::Point(50, 35));
  400. EXPECT_TRUE(d12.received_touch());
  401. EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
  402. d1.reset();
  403. d11.reset();
  404. d12.reset();
  405. d2.reset();
  406. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  407. EXPECT_FALSE(d1.received_touch());
  408. EXPECT_FALSE(d11.received_touch());
  409. EXPECT_TRUE(d12.received_touch());
  410. EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d12.last_event_type());
  411. EXPECT_FALSE(d2.received_touch());
  412. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
  413. }
  414. {
  415. // Adding a modal window while a touch is down in other transient window
  416. // tree should not fire a touch cancel.
  417. wm::ActivateWindow(w2.get());
  418. generator.MoveTouch(gfx::Point(110, 10));
  419. generator.PressTouch();
  420. generator.MoveTouch(gfx::Point(110, 15));
  421. EXPECT_TRUE(d2.received_touch());
  422. EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
  423. d1.reset();
  424. d11.reset();
  425. d12.reset();
  426. d2.reset();
  427. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  428. EXPECT_FALSE(d1.received_touch());
  429. EXPECT_FALSE(d11.received_touch());
  430. EXPECT_FALSE(d12.received_touch());
  431. EXPECT_FALSE(d2.received_touch());
  432. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
  433. }
  434. {
  435. // Adding a child type modal window while a touch is down in other transient
  436. // window tree should not fire a touch cancel. (See
  437. // https://crbug.com/900321)
  438. wm::ActivateWindow(w2.get());
  439. generator.MoveTouch(gfx::Point(110, 10));
  440. generator.PressTouch();
  441. generator.MoveTouch(gfx::Point(110, 15));
  442. EXPECT_TRUE(d2.received_touch());
  443. EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
  444. d1.reset();
  445. d11.reset();
  446. d12.reset();
  447. d2.reset();
  448. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
  449. EXPECT_FALSE(d1.received_touch());
  450. EXPECT_FALSE(d11.received_touch());
  451. EXPECT_FALSE(d12.received_touch());
  452. EXPECT_FALSE(d2.received_touch());
  453. w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
  454. }
  455. }
  456. // Child-modal test.
  457. // Creates:
  458. // - A |top_level| window that hosts a |modal_parent| window within itself. The
  459. // |top_level| and |modal_parent| windows are not the same window. The
  460. // |modal_parent| window is not activatable, because it's contained within the
  461. // |top_level| window.
  462. // - A |modal_child| window with parent window |top_level|, but is modal to
  463. // |modal_parent| window.
  464. // Validates:
  465. // - Clicking on the |modal_parent| should activate the |modal_child| window.
  466. // - Clicking on the |top_level| window outside of the |modal_parent| bounds
  467. // should activate the |top_level| window.
  468. // - Clicking on the |modal_child| while |top_level| is active should activate
  469. // the |modal_child| window.
  470. // - Focus should follow the active window.
  471. TEST_F(WindowModalityControllerTest, ChildModal) {
  472. TestChildModalParent* delegate = TestChildModalParent::Show(GetContext());
  473. aura::Window* top_level = delegate->GetWidget()->GetNativeView();
  474. EXPECT_TRUE(wm::IsActiveWindow(top_level));
  475. aura::Window* modal_parent = delegate->GetModalParent();
  476. EXPECT_NE(nullptr, modal_parent);
  477. EXPECT_NE(top_level, modal_parent);
  478. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  479. aura::Window* modal_child = delegate->ShowModalChild();
  480. EXPECT_NE(nullptr, modal_child);
  481. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  482. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  483. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  484. EXPECT_TRUE(modal_child->HasFocus());
  485. EXPECT_FALSE(modal_parent->HasFocus());
  486. EXPECT_FALSE(top_level->HasFocus());
  487. wm::ActivateWindow(modal_parent);
  488. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  489. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  490. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  491. EXPECT_TRUE(modal_child->HasFocus());
  492. EXPECT_FALSE(modal_parent->HasFocus());
  493. EXPECT_FALSE(top_level->HasFocus());
  494. wm::ActivateWindow(top_level);
  495. EXPECT_FALSE(wm::IsActiveWindow(modal_child));
  496. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  497. EXPECT_TRUE(wm::IsActiveWindow(top_level));
  498. EXPECT_FALSE(modal_child->HasFocus());
  499. EXPECT_FALSE(modal_parent->HasFocus());
  500. EXPECT_TRUE(top_level->HasFocus());
  501. wm::ActivateWindow(modal_child);
  502. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  503. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  504. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  505. EXPECT_TRUE(modal_child->HasFocus());
  506. EXPECT_FALSE(modal_parent->HasFocus());
  507. EXPECT_FALSE(top_level->HasFocus());
  508. }
  509. // Same as |ChildModal| test, but using |EventGenerator| rather than bypassing
  510. // it by calling |ActivateWindow|.
  511. TEST_F(WindowModalityControllerTest, ChildModalEventGenerator) {
  512. TestChildModalParent* delegate = TestChildModalParent::Show(GetContext());
  513. aura::Window* top_level = delegate->GetWidget()->GetNativeView();
  514. EXPECT_TRUE(wm::IsActiveWindow(top_level));
  515. aura::Window* modal_parent = delegate->GetModalParent();
  516. EXPECT_NE(nullptr, modal_parent);
  517. EXPECT_NE(top_level, modal_parent);
  518. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  519. aura::Window* modal_child = delegate->ShowModalChild();
  520. EXPECT_NE(nullptr, modal_child);
  521. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  522. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  523. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  524. EXPECT_TRUE(modal_child->HasFocus());
  525. EXPECT_FALSE(modal_parent->HasFocus());
  526. EXPECT_FALSE(top_level->HasFocus());
  527. {
  528. ui::test::EventGenerator generator(
  529. Shell::GetPrimaryRootWindow(),
  530. top_level->bounds().origin() +
  531. gfx::Vector2d(10, top_level->bounds().height() - 10));
  532. generator.ClickLeftButton();
  533. generator.ClickLeftButton();
  534. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  535. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  536. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  537. EXPECT_TRUE(modal_child->HasFocus());
  538. EXPECT_FALSE(modal_parent->HasFocus());
  539. EXPECT_FALSE(top_level->HasFocus());
  540. }
  541. {
  542. ui::test::EventGenerator generator(
  543. Shell::GetPrimaryRootWindow(),
  544. top_level->bounds().origin() + gfx::Vector2d(10, 10));
  545. generator.ClickLeftButton();
  546. EXPECT_FALSE(wm::IsActiveWindow(modal_child));
  547. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  548. EXPECT_TRUE(wm::IsActiveWindow(top_level));
  549. EXPECT_FALSE(modal_child->HasFocus());
  550. EXPECT_FALSE(modal_parent->HasFocus());
  551. EXPECT_TRUE(top_level->HasFocus());
  552. }
  553. {
  554. ui::test::EventGenerator generator(
  555. Shell::GetPrimaryRootWindow(),
  556. modal_child->bounds().origin() + gfx::Vector2d(10, 10));
  557. generator.ClickLeftButton();
  558. EXPECT_TRUE(wm::IsActiveWindow(modal_child));
  559. EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
  560. EXPECT_FALSE(wm::IsActiveWindow(top_level));
  561. EXPECT_TRUE(modal_child->HasFocus());
  562. EXPECT_FALSE(modal_parent->HasFocus());
  563. EXPECT_FALSE(top_level->HasFocus());
  564. }
  565. }
  566. // Window-modal test for the case when the originally clicked window is an
  567. // ancestor of the modal parent.
  568. TEST_F(WindowModalityControllerTest, WindowModalAncestor) {
  569. aura::test::TestWindowDelegate d;
  570. std::unique_ptr<aura::Window> w1(
  571. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  572. std::unique_ptr<aura::Window> w2(
  573. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
  574. std::unique_ptr<aura::Window> w3(
  575. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w2.get()));
  576. std::unique_ptr<aura::Window> w4(
  577. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  578. w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  579. ::wm::AddTransientChild(w1.get(), w4.get());
  580. wm::ActivateWindow(w1.get());
  581. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  582. wm::ActivateWindow(w2.get());
  583. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  584. wm::ActivateWindow(w3.get());
  585. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  586. wm::ActivateWindow(w4.get());
  587. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  588. }
  589. // Child-modal test for the case when the originally clicked window is an
  590. // ancestor of the modal parent.
  591. TEST_F(WindowModalityControllerTest, ChildModalAncestor) {
  592. aura::test::TestWindowDelegate d;
  593. std::unique_ptr<aura::Window> w1(
  594. CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
  595. std::unique_ptr<aura::Window> w2(
  596. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
  597. std::unique_ptr<aura::Window> w3(
  598. aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w2.get()));
  599. std::unique_ptr<aura::Window> w4(
  600. CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
  601. w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
  602. ::wm::SetModalParent(w4.get(), w2.get());
  603. ::wm::AddTransientChild(w1.get(), w4.get());
  604. wm::ActivateWindow(w1.get());
  605. EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
  606. wm::ActivateWindow(w2.get());
  607. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  608. wm::ActivateWindow(w3.get());
  609. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  610. wm::ActivateWindow(w4.get());
  611. EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
  612. }
  613. } // namespace ash