Roll src/third_party/WebKit 45228d2:a9f98d9 (svn 201149:201150)
[chromium-blink-merge.git] / ash / extended_desktop_unittest.cc
blob64eee29a37cc262582a172252a9fdd734976d115
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.
5 #include "ash/display/display_manager.h"
6 #include "ash/root_window_controller.h"
7 #include "ash/screen_util.h"
8 #include "ash/shell.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/system/tray/system_tray.h"
11 #include "ash/test/ash_test_base.h"
12 #include "ash/wm/coordinate_conversion.h"
13 #include "ash/wm/window_properties.h"
14 #include "ash/wm/window_util.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "ui/aura/client/capture_client.h"
18 #include "ui/aura/client/focus_client.h"
19 #include "ui/aura/test/test_windows.h"
20 #include "ui/aura/test/window_test_api.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_event_dispatcher.h"
23 #include "ui/base/cursor/cursor.h"
24 #include "ui/events/event_handler.h"
25 #include "ui/events/test/event_generator.h"
26 #include "ui/gfx/display.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/views/controls/textfield/textfield.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/views/widget/widget_delegate.h"
31 #include "ui/wm/public/activation_client.h"
33 namespace ash {
34 namespace {
36 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
37 DisplayLayout layout =
38 Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout();
39 layout.position = position;
40 Shell::GetInstance()->display_manager()->
41 SetLayoutForCurrentDisplays(layout);
44 class ModalWidgetDelegate : public views::WidgetDelegateView {
45 public:
46 ModalWidgetDelegate() {}
47 ~ModalWidgetDelegate() override {}
49 // Overridden from views::WidgetDelegate:
50 views::View* GetContentsView() override { return this; }
51 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; }
53 private:
54 DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
57 // An event handler which moves the target window to the secondary root window
58 // at pre-handle phase of a mouse release event.
59 class MoveWindowByClickEventHandler : public ui::EventHandler {
60 public:
61 explicit MoveWindowByClickEventHandler(aura::Window* target)
62 : target_(target) {}
63 ~MoveWindowByClickEventHandler() override {}
65 private:
66 // ui::EventHandler overrides:
67 void OnMouseEvent(ui::MouseEvent* event) override {
68 if (event->type() == ui::ET_MOUSE_RELEASED) {
69 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
70 DCHECK_LT(1u, root_windows.size());
71 root_windows[1]->AddChild(target_);
75 aura::Window* target_;
76 DISALLOW_COPY_AND_ASSIGN(MoveWindowByClickEventHandler);
79 // An event handler which records the event's locations.
80 class EventLocationRecordingEventHandler : public ui::EventHandler {
81 public:
82 explicit EventLocationRecordingEventHandler() {
83 reset();
85 ~EventLocationRecordingEventHandler() override {}
87 std::string GetLocationsAndReset() {
88 std::string result =
89 location_.ToString() + " " + root_location_.ToString();
90 reset();
91 return result;
94 private:
95 // ui::EventHandler overrides:
96 void OnMouseEvent(ui::MouseEvent* event) override {
97 if (event->type() == ui::ET_MOUSE_MOVED ||
98 event->type() == ui::ET_MOUSE_DRAGGED) {
99 location_ = event->location();
100 root_location_ = event->root_location();
104 void reset() {
105 location_.SetPoint(-999, -999);
106 root_location_.SetPoint(-999, -999);
109 gfx::Point root_location_;
110 gfx::Point location_;
112 DISALLOW_COPY_AND_ASSIGN(EventLocationRecordingEventHandler);
115 class EventLocationHandler : public ui::EventHandler {
116 public:
117 EventLocationHandler() {}
118 ~EventLocationHandler() override {}
120 const gfx::Point& press_location() const { return press_location_; }
121 const gfx::Point& release_location() const { return release_location_; }
123 private:
124 // ui::EventHandler:
125 void OnMouseEvent(ui::MouseEvent* event) override {
126 if (event->type() == ui::ET_MOUSE_PRESSED)
127 press_location_ = event->location();
128 else if (event->type() == ui::ET_MOUSE_RELEASED)
129 release_location_ = event->location();
132 gfx::Point press_location_;
133 gfx::Point release_location_;
135 DISALLOW_COPY_AND_ASSIGN(EventLocationHandler);
138 } // namespace
140 class ExtendedDesktopTest : public test::AshTestBase {
141 public:
142 views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
143 return CreateTestWidgetWithParentAndContext(
144 NULL, CurrentContext(), bounds, false);
147 views::Widget* CreateTestWidgetWithParent(views::Widget* parent,
148 const gfx::Rect& bounds,
149 bool child) {
150 CHECK(parent);
151 return CreateTestWidgetWithParentAndContext(parent, NULL, bounds, child);
154 views::Widget* CreateTestWidgetWithParentAndContext(views::Widget* parent,
155 gfx::NativeView context,
156 const gfx::Rect& bounds,
157 bool child) {
158 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
159 if (parent)
160 params.parent = parent->GetNativeView();
161 params.context = context;
162 params.bounds = bounds;
163 params.child = child;
164 views::Widget* widget = new views::Widget;
165 widget->Init(params);
166 widget->Show();
167 return widget;
171 // Test conditions that root windows in extended desktop mode
172 // must satisfy.
173 TEST_F(ExtendedDesktopTest, Basic) {
174 if (!SupportsMultipleDisplays())
175 return;
177 UpdateDisplay("1000x600,600x400");
178 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
180 // All root windows must have the root window controller.
181 ASSERT_EQ(2U, root_windows.size());
182 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
183 iter != root_windows.end(); ++iter) {
184 EXPECT_TRUE(GetRootWindowController(*iter) != NULL);
186 // Make sure root windows share the same controllers.
187 EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
188 aura::client::GetFocusClient(root_windows[1]));
189 EXPECT_EQ(aura::client::GetActivationClient(root_windows[0]),
190 aura::client::GetActivationClient(root_windows[1]));
191 EXPECT_EQ(aura::client::GetCaptureClient(root_windows[0]),
192 aura::client::GetCaptureClient(root_windows[1]));
195 TEST_F(ExtendedDesktopTest, Activation) {
196 if (!SupportsMultipleDisplays())
197 return;
199 UpdateDisplay("1000x600,600x400");
200 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
202 views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
203 views::Widget* widget_on_2nd =
204 CreateTestWidget(gfx::Rect(1200, 10, 100, 100));
205 EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
206 EXPECT_EQ(root_windows[1], widget_on_2nd->GetNativeView()->GetRootWindow());
208 EXPECT_EQ(widget_on_2nd->GetNativeView(),
209 aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
210 EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
212 ui::test::EventGenerator& event_generator(GetEventGenerator());
213 // Clicking a window changes the active window and active root window.
214 event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
215 event_generator.ClickLeftButton();
217 EXPECT_EQ(widget_on_1st->GetNativeView(),
218 aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
219 EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
221 event_generator.MoveMouseToCenterOf(widget_on_2nd->GetNativeView());
222 event_generator.ClickLeftButton();
224 EXPECT_EQ(widget_on_2nd->GetNativeView(),
225 aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
226 EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
229 TEST_F(ExtendedDesktopTest, SystemModal) {
230 if (!SupportsMultipleDisplays())
231 return;
233 UpdateDisplay("1000x600,600x400");
234 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
236 views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
237 EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
238 EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
239 EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
241 // Open system modal. Make sure it's on 2nd root window and active.
242 views::Widget* modal_widget = views::Widget::CreateWindowWithContextAndBounds(
243 new ModalWidgetDelegate(),
244 CurrentContext(),
245 gfx::Rect(1200, 100, 100, 100));
246 modal_widget->Show();
247 EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
248 EXPECT_EQ(root_windows[1], modal_widget->GetNativeView()->GetRootWindow());
249 EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
251 ui::test::EventGenerator& event_generator(GetEventGenerator());
253 // Clicking a widget on widget_on_1st display should not change activation.
254 event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
255 event_generator.ClickLeftButton();
256 EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
257 EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
259 // Close system modal and so clicking a widget should work now.
260 modal_widget->Close();
261 event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
262 event_generator.ClickLeftButton();
263 EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
264 EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
267 TEST_F(ExtendedDesktopTest, TestCursor) {
268 if (!SupportsMultipleDisplays())
269 return;
271 UpdateDisplay("1000x600,600x400");
272 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
273 aura::WindowTreeHost* host0 = root_windows[0]->GetHost();
274 aura::WindowTreeHost* host1 = root_windows[1]->GetHost();
275 EXPECT_EQ(ui::kCursorPointer, host0->last_cursor().native_type());
276 EXPECT_EQ(ui::kCursorPointer, host1->last_cursor().native_type());
277 Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
278 EXPECT_EQ(ui::kCursorCopy, host0->last_cursor().native_type());
279 EXPECT_EQ(ui::kCursorCopy, host1->last_cursor().native_type());
282 TEST_F(ExtendedDesktopTest, TestCursorLocation) {
283 if (!SupportsMultipleDisplays())
284 return;
286 UpdateDisplay("1000x600,600x400");
287 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
288 aura::test::WindowTestApi root_window0_test_api(root_windows[0]);
289 aura::test::WindowTestApi root_window1_test_api(root_windows[1]);
291 root_windows[0]->MoveCursorTo(gfx::Point(10, 10));
292 EXPECT_EQ("10,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
293 EXPECT_TRUE(root_window0_test_api.ContainsMouse());
294 EXPECT_FALSE(root_window1_test_api.ContainsMouse());
295 root_windows[1]->MoveCursorTo(gfx::Point(10, 20));
296 EXPECT_EQ("1010,20", Shell::GetScreen()->GetCursorScreenPoint().ToString());
297 EXPECT_FALSE(root_window0_test_api.ContainsMouse());
298 EXPECT_TRUE(root_window1_test_api.ContainsMouse());
299 root_windows[0]->MoveCursorTo(gfx::Point(20, 10));
300 EXPECT_EQ("20,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
301 EXPECT_TRUE(root_window0_test_api.ContainsMouse());
302 EXPECT_FALSE(root_window1_test_api.ContainsMouse());
305 TEST_F(ExtendedDesktopTest, GetRootWindowAt) {
306 if (!SupportsMultipleDisplays())
307 return;
309 UpdateDisplay("700x500,500x500");
310 SetSecondaryDisplayLayout(DisplayLayout::LEFT);
311 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
313 EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100)));
314 EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-1, 100)));
315 EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 300)));
316 EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(700, 300)));
318 // Zero origin.
319 EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 0)));
321 // Out of range point should return the nearest root window
322 EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-600, 0)));
323 EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(701, 100)));
326 TEST_F(ExtendedDesktopTest, GetRootWindowMatching) {
327 if (!SupportsMultipleDisplays())
328 return;
330 UpdateDisplay("700x500,500x500");
331 SetSecondaryDisplayLayout(DisplayLayout::LEFT);
333 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
335 // Containing rect.
336 EXPECT_EQ(root_windows[1],
337 wm::GetRootWindowMatching(gfx::Rect(-300, 10, 50, 50)));
338 EXPECT_EQ(root_windows[0],
339 wm::GetRootWindowMatching(gfx::Rect(100, 10, 50, 50)));
341 // Intersecting rect.
342 EXPECT_EQ(root_windows[1],
343 wm::GetRootWindowMatching(gfx::Rect(-200, 0, 300, 300)));
344 EXPECT_EQ(root_windows[0],
345 wm::GetRootWindowMatching(gfx::Rect(-100, 0, 300, 300)));
347 // Zero origin.
348 EXPECT_EQ(root_windows[0],
349 wm::GetRootWindowMatching(gfx::Rect(0, 0, 0, 0)));
350 EXPECT_EQ(root_windows[0],
351 wm::GetRootWindowMatching(gfx::Rect(0, 0, 1, 1)));
353 // Empty rect.
354 EXPECT_EQ(root_windows[1],
355 wm::GetRootWindowMatching(gfx::Rect(-400, 100, 0, 0)));
356 EXPECT_EQ(root_windows[0],
357 wm::GetRootWindowMatching(gfx::Rect(100, 100, 0, 0)));
359 // Out of range rect should return the primary root window.
360 EXPECT_EQ(root_windows[0],
361 wm::GetRootWindowMatching(gfx::Rect(-600, -300, 50, 50)));
362 EXPECT_EQ(root_windows[0],
363 wm::GetRootWindowMatching(gfx::Rect(0, 1000, 50, 50)));
366 TEST_F(ExtendedDesktopTest, Capture) {
367 if (!SupportsMultipleDisplays())
368 return;
370 UpdateDisplay("1000x600,600x400");
371 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
373 aura::test::EventCountDelegate r1_d1;
374 aura::test::EventCountDelegate r1_d2;
375 aura::test::EventCountDelegate r2_d1;
377 scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
378 &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
379 scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
380 &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
381 scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
382 &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
384 r1_w1->SetCapture();
386 EXPECT_EQ(r1_w1.get(),
387 aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
389 ui::test::EventGenerator& generator = GetEventGenerator();
390 generator.MoveMouseToCenterOf(r2_w1.get());
391 // |r1_w1| will receive the events because it has capture.
392 EXPECT_EQ("1 1 0", r1_d1.GetMouseMotionCountsAndReset());
393 EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
394 EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
396 generator.ClickLeftButton();
397 EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
398 EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
399 // The mouse is outside. On chromeos, the mouse is warped to the
400 // dest root window, but it's not implemented on Win yet, so
401 // no mouse move event on Win.
402 EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
403 EXPECT_EQ("1 1", r1_d1.GetMouseButtonCountsAndReset());
405 generator.MoveMouseTo(15, 15);
406 EXPECT_EQ("0 1 0", r1_d1.GetMouseMotionCountsAndReset());
407 EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
409 r1_w2->SetCapture();
410 EXPECT_EQ(r1_w2.get(),
411 aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
412 generator.MoveMouseBy(10, 10);
413 // |r1_w2| has the capture. So it will receive the mouse-move event.
414 EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
415 EXPECT_EQ("0 1 0", r1_d2.GetMouseMotionCountsAndReset());
416 EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
418 generator.ClickLeftButton();
419 EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
420 EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
421 EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
422 EXPECT_EQ("1 1", r1_d2.GetMouseButtonCountsAndReset());
424 r1_w2->ReleaseCapture();
425 EXPECT_EQ(NULL, aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
427 generator.MoveMouseToCenterOf(r2_w1.get());
428 generator.ClickLeftButton();
429 EXPECT_EQ("1 1 0", r2_d1.GetMouseMotionCountsAndReset());
430 EXPECT_EQ("1 1", r2_d1.GetMouseButtonCountsAndReset());
431 // Make sure the mouse_moved_handler_ is properly reset.
432 EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
433 EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset());
436 TEST_F(ExtendedDesktopTest, CaptureEventLocation) {
437 if (!SupportsMultipleDisplays())
438 return;
440 UpdateDisplay("1000x600,600x400");
441 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
443 aura::test::EventCountDelegate r1_d1;
444 aura::test::EventCountDelegate r1_d2;
445 aura::test::EventCountDelegate r2_d1;
447 scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
448 &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
449 scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
450 &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
451 scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
452 &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
454 r1_w1->SetCapture();
456 ui::test::EventGenerator& generator = GetEventGenerator();
457 generator.MoveMouseToCenterOf(r2_w1.get());
458 EXPECT_EQ(gfx::Point(1060, 60).ToString(),
459 generator.current_location().ToString());
461 EventLocationHandler location_handler;
462 r1_w1->AddPreTargetHandler(&location_handler);
463 generator.ClickLeftButton();
464 r1_w1->RemovePreTargetHandler(&location_handler);
465 EXPECT_EQ(gfx::Point(1050, 50).ToString(),
466 location_handler.press_location().ToString());
467 EXPECT_EQ(gfx::Point(1050, 50).ToString(),
468 location_handler.release_location().ToString());
471 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI) {
472 if (!SupportsMultipleDisplays())
473 return;
475 UpdateDisplay("1000x600*2,600x400");
476 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
478 aura::test::EventCountDelegate r1_d1;
479 aura::test::EventCountDelegate r1_d2;
480 aura::test::EventCountDelegate r2_d1;
482 scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
483 &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
484 scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
485 &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
486 scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
487 &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
489 r1_w1->SetCapture();
491 ui::test::EventGenerator& generator = GetEventGenerator();
492 generator.MoveMouseToCenterOf(r2_w1.get());
493 EXPECT_EQ(gfx::Point(560, 60).ToString(),
494 generator.current_location().ToString());
496 EventLocationHandler location_handler;
497 r1_w1->AddPreTargetHandler(&location_handler);
498 generator.ClickLeftButton();
499 r1_w1->RemovePreTargetHandler(&location_handler);
500 EXPECT_EQ(gfx::Point(550, 50).ToString(),
501 location_handler.press_location().ToString());
502 EXPECT_EQ(gfx::Point(550, 50).ToString(),
503 location_handler.release_location().ToString());
506 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI_2) {
507 if (!SupportsMultipleDisplays())
508 return;
510 UpdateDisplay("1000x600,600x400*2");
511 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
513 aura::test::EventCountDelegate r1_d1;
514 aura::test::EventCountDelegate r1_d2;
515 aura::test::EventCountDelegate r2_d1;
517 scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
518 &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
519 scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
520 &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
521 scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
522 &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
524 r1_w1->SetCapture();
526 ui::test::EventGenerator& generator = GetEventGenerator();
527 generator.MoveMouseToCenterOf(r2_w1.get());
528 EXPECT_EQ(gfx::Point(1060, 60).ToString(),
529 generator.current_location().ToString());
531 EventLocationHandler location_handler;
532 r1_w1->AddPreTargetHandler(&location_handler);
533 generator.ClickLeftButton();
534 r1_w1->RemovePreTargetHandler(&location_handler);
535 // Event-generator dispatches the event in the primary root-window's coord
536 // space. Since the location is (1060, 60), it goes to the secondary
537 // root-window as (30, 30) since the secondary root-window has a device scale
538 // factor of 2.
539 EXPECT_EQ(gfx::Point(1020, 20).ToString(),
540 location_handler.press_location().ToString());
541 EXPECT_EQ(gfx::Point(1020, 20).ToString(),
542 location_handler.release_location().ToString());
545 TEST_F(ExtendedDesktopTest, MoveWindow) {
546 if (!SupportsMultipleDisplays())
547 return;
549 UpdateDisplay("1000x600,600x400");
550 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
551 views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
553 EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
555 d1->SetBounds(gfx::Rect(1010, 10, 100, 100));
556 EXPECT_EQ("1010,10 100x100",
557 d1->GetWindowBoundsInScreen().ToString());
559 EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
561 d1->SetBounds(gfx::Rect(10, 10, 100, 100));
562 EXPECT_EQ("10,10 100x100",
563 d1->GetWindowBoundsInScreen().ToString());
565 EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
567 // Make sure the bounds which doesn't fit to the root window
568 // works correctly.
569 d1->SetBounds(gfx::Rect(1560, 30, 100, 100));
570 EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
571 EXPECT_EQ("1560,30 100x100",
572 d1->GetWindowBoundsInScreen().ToString());
574 // Setting outside of root windows will be moved to primary root window.
575 // TODO(oshima): This one probably should pick the closest root window.
576 d1->SetBounds(gfx::Rect(200, 10, 100, 100));
577 EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
580 // Verifies if the mouse event arrives to the window even when the window
581 // moves to another root in a pre-target handler. See: crbug.com/157583
582 TEST_F(ExtendedDesktopTest, MoveWindowByMouseClick) {
583 if (!SupportsMultipleDisplays())
584 return;
586 UpdateDisplay("1000x600,600x400");
588 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
589 aura::test::EventCountDelegate delegate;
590 scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
591 &delegate, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
592 MoveWindowByClickEventHandler event_handler(window.get());
593 window->AddPreTargetHandler(&event_handler);
595 ui::test::EventGenerator& event_generator(GetEventGenerator());
597 event_generator.MoveMouseToCenterOf(window.get());
598 event_generator.ClickLeftButton();
599 // Both mouse pressed and released arrive at the window and its delegate.
600 EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
601 // Also event_handler moves the window to another root at mouse release.
602 EXPECT_EQ(root_windows[1], window->GetRootWindow());
605 TEST_F(ExtendedDesktopTest, MoveWindowToDisplay) {
606 if (!SupportsMultipleDisplays())
607 return;
609 UpdateDisplay("1000x1000,1000x1000");
610 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
612 gfx::Display display0 = Shell::GetScreen()->GetDisplayMatching(
613 root_windows[0]->GetBoundsInScreen());
614 gfx::Display display1 = Shell::GetScreen()->GetDisplayMatching(
615 root_windows[1]->GetBoundsInScreen());
616 EXPECT_NE(display0.id(), display1.id());
618 views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 1000, 100));
619 EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
621 // Move the window where the window spans both root windows. Since the second
622 // parameter is |display1|, the window should be shown on the secondary root.
623 d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
624 display1);
625 EXPECT_EQ("500,10 1000x100",
626 d1->GetWindowBoundsInScreen().ToString());
627 EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
629 // Move to the primary root.
630 d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
631 display0);
632 EXPECT_EQ("500,10 1000x100",
633 d1->GetWindowBoundsInScreen().ToString());
634 EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
637 TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) {
638 if (!SupportsMultipleDisplays())
639 return;
641 UpdateDisplay("1000x600,600x400");
642 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
643 views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
644 views::Widget* w1_t1 = CreateTestWidgetWithParent(
645 w1, gfx::Rect(50, 50, 50, 50), false /* transient */);
646 // Transient child of the transient child.
647 views::Widget* w1_t11 = CreateTestWidgetWithParent(
648 w1_t1, gfx::Rect(1200, 70, 35, 35), false /* transient */);
650 views::Widget* w11 = CreateTestWidgetWithParent(
651 w1, gfx::Rect(10, 10, 40, 40), true /* child */);
652 views::Widget* w11_t1 = CreateTestWidgetWithParent(
653 w1, gfx::Rect(1300, 100, 80, 80), false /* transient */);
655 EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
656 EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow());
657 EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow());
658 EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow());
659 EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow());
660 EXPECT_EQ("50,50 50x50",
661 w1_t1->GetWindowBoundsInScreen().ToString());
662 EXPECT_EQ("1200,70 35x35",
663 w1_t11->GetWindowBoundsInScreen().ToString());
664 EXPECT_EQ("20,20 40x40",
665 w11->GetWindowBoundsInScreen().ToString());
666 EXPECT_EQ("1300,100 80x80",
667 w11_t1->GetWindowBoundsInScreen().ToString());
669 w1->SetBounds(gfx::Rect(1100, 10, 100, 100));
671 EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
672 EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
673 EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow());
674 EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow());
675 EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow());
677 EXPECT_EQ("1110,20 40x40",
678 w11->GetWindowBoundsInScreen().ToString());
679 // Transient window's screen bounds stays the same.
680 EXPECT_EQ("50,50 50x50",
681 w1_t1->GetWindowBoundsInScreen().ToString());
682 EXPECT_EQ("1200,70 35x35",
683 w1_t11->GetWindowBoundsInScreen().ToString());
684 EXPECT_EQ("1300,100 80x80",
685 w11_t1->GetWindowBoundsInScreen().ToString());
687 // Transient window doesn't move between root window unless
688 // its transient parent moves.
689 w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50));
690 EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
691 EXPECT_EQ("10,50 50x50",
692 w1_t1->GetWindowBoundsInScreen().ToString());
695 // Test if the Window::ConvertPointToTarget works across root windows.
696 // TODO(oshima): Move multiple display suport and this test to aura.
697 TEST_F(ExtendedDesktopTest, ConvertPoint) {
698 if (!SupportsMultipleDisplays())
699 return;
700 gfx::Screen* screen = Shell::GetScreen();
701 UpdateDisplay("1000x600,600x400");
702 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
703 gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
704 EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
705 gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
706 EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
708 aura::Window* d1 =
709 CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
710 aura::Window* d2 =
711 CreateTestWidget(gfx::Rect(1020, 20, 100, 100))->GetNativeView();
712 EXPECT_EQ(root_windows[0], d1->GetRootWindow());
713 EXPECT_EQ(root_windows[1], d2->GetRootWindow());
715 // Convert point in the Root2's window to the Root1's window Coord.
716 gfx::Point p(0, 0);
717 aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
718 EXPECT_EQ("1000,0", p.ToString());
719 p.SetPoint(0, 0);
720 aura::Window::ConvertPointToTarget(d2, d1, &p);
721 EXPECT_EQ("1010,10", p.ToString());
723 // Convert point in the Root1's window to the Root2's window Coord.
724 p.SetPoint(0, 0);
725 aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
726 EXPECT_EQ("-1000,0", p.ToString());
727 p.SetPoint(0, 0);
728 aura::Window::ConvertPointToTarget(d1, d2, &p);
729 EXPECT_EQ("-1010,-10", p.ToString());
731 // Move the 2nd display to the bottom and test again.
732 SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
734 display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
735 EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
737 // Convert point in Root2's window to Root1's window Coord.
738 p.SetPoint(0, 0);
739 aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
740 EXPECT_EQ("0,600", p.ToString());
741 p.SetPoint(0, 0);
742 aura::Window::ConvertPointToTarget(d2, d1, &p);
743 EXPECT_EQ("10,610", p.ToString());
745 // Convert point in Root1's window to Root2's window Coord.
746 p.SetPoint(0, 0);
747 aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
748 EXPECT_EQ("0,-600", p.ToString());
749 p.SetPoint(0, 0);
750 aura::Window::ConvertPointToTarget(d1, d2, &p);
751 EXPECT_EQ("-10,-610", p.ToString());
754 TEST_F(ExtendedDesktopTest, OpenSystemTray) {
755 if (!SupportsMultipleDisplays())
756 return;
758 UpdateDisplay("500x600,600x400");
759 SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
760 ASSERT_FALSE(tray->HasSystemBubble());
762 ui::test::EventGenerator& event_generator(GetEventGenerator());
764 // Opens the tray by a dummy click event and makes sure that adding/removing
765 // displays doesn't break anything.
766 event_generator.MoveMouseToCenterOf(tray->GetWidget()->GetNativeWindow());
767 event_generator.ClickLeftButton();
768 EXPECT_TRUE(tray->HasSystemBubble());
770 UpdateDisplay("500x600");
771 EXPECT_TRUE(tray->HasSystemBubble());
772 UpdateDisplay("500x600,600x400");
773 EXPECT_TRUE(tray->HasSystemBubble());
775 // Closes the tray and again makes sure that adding/removing displays doesn't
776 // break anything.
777 event_generator.ClickLeftButton();
778 RunAllPendingInMessageLoop();
780 EXPECT_FALSE(tray->HasSystemBubble());
782 UpdateDisplay("500x600");
783 EXPECT_FALSE(tray->HasSystemBubble());
784 UpdateDisplay("500x600,600x400");
785 EXPECT_FALSE(tray->HasSystemBubble());
788 TEST_F(ExtendedDesktopTest, StayInSameRootWindow) {
789 if (!SupportsMultipleDisplays())
790 return;
792 UpdateDisplay("100x100,200x200");
793 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
794 views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 50, 50));
795 EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
796 w1->SetBounds(gfx::Rect(150, 10, 50, 50));
797 EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
799 // The widget stays in the same root if kStayInSameRootWindowKey is set to
800 // true.
801 w1->GetNativeView()->SetProperty(kStayInSameRootWindowKey, true);
802 w1->SetBounds(gfx::Rect(10, 10, 50, 50));
803 EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
805 // The widget should now move to the 1st root window without the property.
806 w1->GetNativeView()->ClearProperty(kStayInSameRootWindowKey);
807 w1->SetBounds(gfx::Rect(10, 10, 50, 50));
808 EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
810 // a window in SettingsBubbleContainer and StatusContainer should
811 // not move to another root window regardles of the bounds specified.
812 aura::Window* settings_bubble_container =
813 Shell::GetPrimaryRootWindowController()->GetContainer(
814 kShellWindowId_SettingBubbleContainer);
815 aura::Window* window = aura::test::CreateTestWindowWithId(
816 100, settings_bubble_container);
817 window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
818 ScreenUtil::GetSecondaryDisplay());
819 EXPECT_EQ(root_windows[0], window->GetRootWindow());
821 aura::Window* status_container =
822 Shell::GetPrimaryRootWindowController()->GetContainer(
823 kShellWindowId_StatusContainer);
824 window = aura::test::CreateTestWindowWithId(100, status_container);
825 window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
826 ScreenUtil::GetSecondaryDisplay());
827 EXPECT_EQ(root_windows[0], window->GetRootWindow());
830 TEST_F(ExtendedDesktopTest, KeyEventsOnLockScreen) {
831 if (!SupportsMultipleDisplays())
832 return;
834 UpdateDisplay("100x100,200x200");
835 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
837 // Create normal windows on both displays.
838 views::Widget* widget1 = CreateTestWidget(
839 Shell::GetScreen()->GetPrimaryDisplay().bounds());
840 widget1->Show();
841 EXPECT_EQ(root_windows[0], widget1->GetNativeView()->GetRootWindow());
842 views::Widget* widget2 = CreateTestWidget(
843 ScreenUtil::GetSecondaryDisplay().bounds());
844 widget2->Show();
845 EXPECT_EQ(root_windows[1], widget2->GetNativeView()->GetRootWindow());
847 // Create a LockScreen window.
848 views::Widget* lock_widget = CreateTestWidget(
849 Shell::GetScreen()->GetPrimaryDisplay().bounds());
850 views::Textfield* textfield = new views::Textfield;
851 lock_widget->client_view()->AddChildView(textfield);
853 ash::Shell::GetContainer(Shell::GetPrimaryRootWindow(),
854 ash::kShellWindowId_LockScreenContainer)
855 ->AddChild(lock_widget->GetNativeView());
856 lock_widget->Show();
857 textfield->RequestFocus();
859 aura::client::FocusClient* focus_client =
860 aura::client::GetFocusClient(root_windows[0]);
861 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
863 // The lock window should get events on both root windows.
864 ui::test::EventGenerator& event_generator(GetEventGenerator());
866 event_generator.set_current_target(root_windows[0]);
867 event_generator.PressKey(ui::VKEY_A, 0);
868 event_generator.ReleaseKey(ui::VKEY_A, 0);
869 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
870 EXPECT_EQ("a", base::UTF16ToASCII(textfield->text()));
872 event_generator.set_current_target(root_windows[1]);
873 event_generator.PressKey(ui::VKEY_B, 0);
874 event_generator.ReleaseKey(ui::VKEY_B, 0);
875 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
876 EXPECT_EQ("ab", base::UTF16ToASCII(textfield->text()));
878 // Deleting 2nd display. The lock window still should get the events.
879 UpdateDisplay("100x100");
880 event_generator.set_current_target(root_windows[0]);
881 event_generator.PressKey(ui::VKEY_C, 0);
882 event_generator.ReleaseKey(ui::VKEY_C, 0);
883 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
884 EXPECT_EQ("abc", base::UTF16ToASCII(textfield->text()));
886 // Creating 2nd display again, and lock window still should get events
887 // on both root windows.
888 UpdateDisplay("100x100,200x200");
889 root_windows = Shell::GetAllRootWindows();
890 event_generator.set_current_target(root_windows[0]);
891 event_generator.PressKey(ui::VKEY_D, 0);
892 event_generator.ReleaseKey(ui::VKEY_D, 0);
893 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
894 EXPECT_EQ("abcd", base::UTF16ToASCII(textfield->text()));
896 event_generator.set_current_target(root_windows[1]);
897 event_generator.PressKey(ui::VKEY_E, 0);
898 event_generator.ReleaseKey(ui::VKEY_E, 0);
899 EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
900 EXPECT_EQ("abcde", base::UTF16ToASCII(textfield->text()));
903 TEST_F(ExtendedDesktopTest, PassiveGrab) {
904 if (!SupportsMultipleDisplays())
905 return;
907 EventLocationRecordingEventHandler event_handler;
908 ash::Shell::GetInstance()->AddPreTargetHandler(&event_handler);
910 UpdateDisplay("300x300,200x200");
912 views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
913 widget->Show();
914 ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
916 ui::test::EventGenerator& generator(GetEventGenerator());
917 generator.MoveMouseTo(150, 150);
918 EXPECT_EQ("100,100 150,150", event_handler.GetLocationsAndReset());
920 generator.PressLeftButton();
921 generator.MoveMouseTo(400, 150);
923 EXPECT_EQ("350,100 400,150", event_handler.GetLocationsAndReset());
925 generator.ReleaseLeftButton();
926 EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
928 generator.MoveMouseTo(400, 150);
929 EXPECT_EQ("100,150 100,150", event_handler.GetLocationsAndReset());
931 ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
934 } // namespace ash