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"
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"
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
{
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
; }
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
{
61 explicit MoveWindowByClickEventHandler(aura::Window
* target
)
63 ~MoveWindowByClickEventHandler() override
{}
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
{
82 explicit EventLocationRecordingEventHandler() {
85 ~EventLocationRecordingEventHandler() override
{}
87 std::string
GetLocationsAndReset() {
89 location_
.ToString() + " " + root_location_
.ToString();
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();
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
{
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_
; }
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
);
140 class ExtendedDesktopTest
: public test::AshTestBase
{
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
,
151 return CreateTestWidgetWithParentAndContext(parent
, NULL
, bounds
, child
);
154 views::Widget
* CreateTestWidgetWithParentAndContext(views::Widget
* parent
,
155 gfx::NativeView context
,
156 const gfx::Rect
& bounds
,
158 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
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
);
171 // Test conditions that root windows in extended desktop mode
173 TEST_F(ExtendedDesktopTest
, Basic
) {
174 if (!SupportsMultipleDisplays())
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())
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())
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(),
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())
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())
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())
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)));
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())
330 UpdateDisplay("700x500,500x500");
331 SetSecondaryDisplayLayout(DisplayLayout::LEFT
);
333 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
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)));
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)));
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())
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]));
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());
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())
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]));
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())
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]));
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())
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]));
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
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())
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
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())
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())
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),
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),
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())
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())
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());
709 CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
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.
717 aura::Window::ConvertPointToTarget(root_windows
[1], root_windows
[0], &p
);
718 EXPECT_EQ("1000,0", p
.ToString());
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.
725 aura::Window::ConvertPointToTarget(root_windows
[0], root_windows
[1], &p
);
726 EXPECT_EQ("-1000,0", p
.ToString());
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.
739 aura::Window::ConvertPointToTarget(root_windows
[1], root_windows
[0], &p
);
740 EXPECT_EQ("0,600", p
.ToString());
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.
747 aura::Window::ConvertPointToTarget(root_windows
[0], root_windows
[1], &p
);
748 EXPECT_EQ("0,-600", p
.ToString());
750 aura::Window::ConvertPointToTarget(d1
, d2
, &p
);
751 EXPECT_EQ("-10,-610", p
.ToString());
754 TEST_F(ExtendedDesktopTest
, OpenSystemTray
) {
755 if (!SupportsMultipleDisplays())
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
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())
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
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())
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());
841 EXPECT_EQ(root_windows
[0], widget1
->GetNativeView()->GetRootWindow());
842 views::Widget
* widget2
= CreateTestWidget(
843 ScreenUtil::GetSecondaryDisplay().bounds());
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());
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())
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));
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
);