• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #include "ash/display/display_controller.h"
6 #include "ash/display/display_manager.h"
7 #include "ash/root_window_controller.h"
8 #include "ash/screen_util.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/system/tray/system_tray.h"
12 #include "ash/test/ash_test_base.h"
13 #include "ash/wm/coordinate_conversion.h"
14 #include "ash/wm/window_properties.h"
15 #include "ash/wm/window_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "ui/aura/client/capture_client.h"
19 #include "ui/aura/client/focus_client.h"
20 #include "ui/aura/test/event_generator.h"
21 #include "ui/aura/test/test_windows.h"
22 #include "ui/aura/test/window_test_api.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_event_dispatcher.h"
25 #include "ui/base/cursor/cursor.h"
26 #include "ui/events/event_handler.h"
27 #include "ui/gfx/display.h"
28 #include "ui/gfx/screen.h"
29 #include "ui/views/controls/textfield/textfield.h"
30 #include "ui/views/widget/widget.h"
31 #include "ui/views/widget/widget_delegate.h"
32 #include "ui/wm/public/activation_client.h"
33 
34 namespace ash {
35 namespace {
36 
SetSecondaryDisplayLayout(DisplayLayout::Position position)37 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
38   DisplayLayout layout =
39       Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout();
40   layout.position = position;
41   Shell::GetInstance()->display_manager()->
42       SetLayoutForCurrentDisplays(layout);
43 }
44 
45 class ModalWidgetDelegate : public views::WidgetDelegateView {
46  public:
ModalWidgetDelegate()47   ModalWidgetDelegate() {}
~ModalWidgetDelegate()48   virtual ~ModalWidgetDelegate() {}
49 
50   // Overridden from views::WidgetDelegate:
GetContentsView()51   virtual views::View* GetContentsView() OVERRIDE {
52     return this;
53   }
GetModalType() const54   virtual ui::ModalType GetModalType() const OVERRIDE {
55     return ui::MODAL_TYPE_SYSTEM;
56   }
57 
58  private:
59   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
60 };
61 
62 // An event handler which moves the target window to the secondary root window
63 // at pre-handle phase of a mouse release event.
64 class MoveWindowByClickEventHandler : public ui::EventHandler {
65  public:
MoveWindowByClickEventHandler(aura::Window * target)66   explicit MoveWindowByClickEventHandler(aura::Window* target)
67       : target_(target) {}
~MoveWindowByClickEventHandler()68   virtual ~MoveWindowByClickEventHandler() {}
69 
70  private:
71   // ui::EventHandler overrides:
OnMouseEvent(ui::MouseEvent * event)72   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
73     if (event->type() == ui::ET_MOUSE_RELEASED) {
74       aura::Window::Windows root_windows = Shell::GetAllRootWindows();
75       DCHECK_LT(1u, root_windows.size());
76       root_windows[1]->AddChild(target_);
77     }
78   }
79 
80   aura::Window* target_;
81   DISALLOW_COPY_AND_ASSIGN(MoveWindowByClickEventHandler);
82 };
83 
84 // An event handler which records the event's locations.
85 class EventLocationRecordingEventHandler : public ui::EventHandler {
86  public:
EventLocationRecordingEventHandler()87   explicit EventLocationRecordingEventHandler() {
88     reset();
89   }
~EventLocationRecordingEventHandler()90   virtual ~EventLocationRecordingEventHandler() {}
91 
GetLocationsAndReset()92   std::string GetLocationsAndReset() {
93     std::string result =
94         location_.ToString() + " " + root_location_.ToString();
95     reset();
96     return result;
97   }
98 
99  private:
100   // ui::EventHandler overrides:
OnMouseEvent(ui::MouseEvent * event)101   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
102     if (event->type() == ui::ET_MOUSE_MOVED ||
103         event->type() == ui::ET_MOUSE_DRAGGED) {
104       location_ = event->location();
105       root_location_ = event->root_location();
106     }
107   }
108 
reset()109   void reset() {
110     location_.SetPoint(-999, -999);
111     root_location_.SetPoint(-999, -999);
112   }
113 
114   gfx::Point root_location_;
115   gfx::Point location_;
116 
117   DISALLOW_COPY_AND_ASSIGN(EventLocationRecordingEventHandler);
118 };
119 
120 }  // namespace
121 
122 class ExtendedDesktopTest : public test::AshTestBase {
123  public:
CreateTestWidget(const gfx::Rect & bounds)124   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
125     return CreateTestWidgetWithParentAndContext(
126         NULL, CurrentContext(), bounds, false);
127   }
128 
CreateTestWidgetWithParent(views::Widget * parent,const gfx::Rect & bounds,bool child)129   views::Widget* CreateTestWidgetWithParent(views::Widget* parent,
130                                             const gfx::Rect& bounds,
131                                             bool child) {
132     CHECK(parent);
133     return CreateTestWidgetWithParentAndContext(parent, NULL, bounds, child);
134   }
135 
CreateTestWidgetWithParentAndContext(views::Widget * parent,gfx::NativeView context,const gfx::Rect & bounds,bool child)136   views::Widget* CreateTestWidgetWithParentAndContext(views::Widget* parent,
137                                                       gfx::NativeView context,
138                                                       const gfx::Rect& bounds,
139                                                       bool child) {
140     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
141     if (parent)
142       params.parent = parent->GetNativeView();
143     params.context = context;
144     params.bounds = bounds;
145     params.child = child;
146     views::Widget* widget = new views::Widget;
147     widget->Init(params);
148     widget->Show();
149     return widget;
150   }
151 };
152 
153 // Test conditions that root windows in extended desktop mode
154 // must satisfy.
TEST_F(ExtendedDesktopTest,Basic)155 TEST_F(ExtendedDesktopTest, Basic) {
156   if (!SupportsMultipleDisplays())
157     return;
158 
159   UpdateDisplay("1000x600,600x400");
160   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
161 
162   // All root windows must have the root window controller.
163   ASSERT_EQ(2U, root_windows.size());
164   for (aura::Window::Windows::const_iterator iter = root_windows.begin();
165        iter != root_windows.end(); ++iter) {
166     EXPECT_TRUE(GetRootWindowController(*iter) != NULL);
167   }
168   // Make sure root windows share the same controllers.
169   EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
170             aura::client::GetFocusClient(root_windows[1]));
171   EXPECT_EQ(aura::client::GetActivationClient(root_windows[0]),
172             aura::client::GetActivationClient(root_windows[1]));
173   EXPECT_EQ(aura::client::GetCaptureClient(root_windows[0]),
174             aura::client::GetCaptureClient(root_windows[1]));
175 }
176 
TEST_F(ExtendedDesktopTest,Activation)177 TEST_F(ExtendedDesktopTest, Activation) {
178   if (!SupportsMultipleDisplays())
179     return;
180 
181   UpdateDisplay("1000x600,600x400");
182   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
183 
184   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
185   views::Widget* widget_on_2nd =
186       CreateTestWidget(gfx::Rect(1200, 10, 100, 100));
187   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
188   EXPECT_EQ(root_windows[1], widget_on_2nd->GetNativeView()->GetRootWindow());
189 
190   EXPECT_EQ(widget_on_2nd->GetNativeView(),
191             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
192   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
193 
194   aura::test::EventGenerator& event_generator(GetEventGenerator());
195   // Clicking a window changes the active window and active root window.
196   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
197   event_generator.ClickLeftButton();
198 
199   EXPECT_EQ(widget_on_1st->GetNativeView(),
200             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
201   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
202 
203   event_generator.MoveMouseToCenterOf(widget_on_2nd->GetNativeView());
204   event_generator.ClickLeftButton();
205 
206   EXPECT_EQ(widget_on_2nd->GetNativeView(),
207             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
208   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
209 }
210 
TEST_F(ExtendedDesktopTest,SystemModal)211 TEST_F(ExtendedDesktopTest, SystemModal) {
212   if (!SupportsMultipleDisplays())
213     return;
214 
215   UpdateDisplay("1000x600,600x400");
216   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
217 
218   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
219   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
220   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
221   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
222 
223   // Open system modal. Make sure it's on 2nd root window and active.
224   views::Widget* modal_widget = views::Widget::CreateWindowWithContextAndBounds(
225       new ModalWidgetDelegate(),
226       CurrentContext(),
227       gfx::Rect(1200, 100, 100, 100));
228   modal_widget->Show();
229   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
230   EXPECT_EQ(root_windows[1], modal_widget->GetNativeView()->GetRootWindow());
231   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
232 
233   aura::test::EventGenerator& event_generator(GetEventGenerator());
234 
235   // Clicking a widget on widget_on_1st display should not change activation.
236   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
237   event_generator.ClickLeftButton();
238   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
239   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
240 
241   // Close system modal and so clicking a widget should work now.
242   modal_widget->Close();
243   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
244   event_generator.ClickLeftButton();
245   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
246   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
247 }
248 
TEST_F(ExtendedDesktopTest,TestCursor)249 TEST_F(ExtendedDesktopTest, TestCursor) {
250   if (!SupportsMultipleDisplays())
251     return;
252 
253   UpdateDisplay("1000x600,600x400");
254   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
255   aura::WindowTreeHost* host0 = root_windows[0]->GetHost();
256   aura::WindowTreeHost* host1 = root_windows[1]->GetHost();
257   EXPECT_EQ(ui::kCursorPointer, host0->last_cursor().native_type());
258   EXPECT_EQ(ui::kCursorPointer, host1->last_cursor().native_type());
259   Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
260   EXPECT_EQ(ui::kCursorCopy, host0->last_cursor().native_type());
261   EXPECT_EQ(ui::kCursorCopy, host1->last_cursor().native_type());
262 }
263 
TEST_F(ExtendedDesktopTest,TestCursorLocation)264 TEST_F(ExtendedDesktopTest, TestCursorLocation) {
265   if (!SupportsMultipleDisplays())
266     return;
267 
268   UpdateDisplay("1000x600,600x400");
269   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
270   aura::test::WindowTestApi root_window0_test_api(root_windows[0]);
271   aura::test::WindowTestApi root_window1_test_api(root_windows[1]);
272 
273   root_windows[0]->MoveCursorTo(gfx::Point(10, 10));
274   EXPECT_EQ("10,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
275   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
276   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
277   root_windows[1]->MoveCursorTo(gfx::Point(10, 20));
278   EXPECT_EQ("1010,20", Shell::GetScreen()->GetCursorScreenPoint().ToString());
279   EXPECT_FALSE(root_window0_test_api.ContainsMouse());
280   EXPECT_TRUE(root_window1_test_api.ContainsMouse());
281   root_windows[0]->MoveCursorTo(gfx::Point(20, 10));
282   EXPECT_EQ("20,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
283   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
284   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
285 }
286 
TEST_F(ExtendedDesktopTest,GetRootWindowAt)287 TEST_F(ExtendedDesktopTest, GetRootWindowAt) {
288   if (!SupportsMultipleDisplays())
289     return;
290 
291   UpdateDisplay("700x500,500x500");
292   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
293   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
294 
295   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100)));
296   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-1, 100)));
297   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 300)));
298   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(700,300)));
299 
300   // Zero origin.
301   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 0)));
302 
303   // Out of range point should return the nearest root window
304   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-600, 0)));
305   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(701, 100)));
306 }
307 
TEST_F(ExtendedDesktopTest,GetRootWindowMatching)308 TEST_F(ExtendedDesktopTest, GetRootWindowMatching) {
309   if (!SupportsMultipleDisplays())
310     return;
311 
312   UpdateDisplay("700x500,500x500");
313   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
314 
315   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
316 
317   // Containing rect.
318   EXPECT_EQ(root_windows[1],
319             wm::GetRootWindowMatching(gfx::Rect(-300, 10, 50, 50)));
320   EXPECT_EQ(root_windows[0],
321             wm::GetRootWindowMatching(gfx::Rect(100, 10, 50, 50)));
322 
323   // Intersecting rect.
324   EXPECT_EQ(root_windows[1],
325             wm::GetRootWindowMatching(gfx::Rect(-200, 0, 300, 300)));
326   EXPECT_EQ(root_windows[0],
327             wm::GetRootWindowMatching(gfx::Rect(-100, 0, 300, 300)));
328 
329   // Zero origin.
330   EXPECT_EQ(root_windows[0],
331             wm::GetRootWindowMatching(gfx::Rect(0, 0, 0, 0)));
332   EXPECT_EQ(root_windows[0],
333             wm::GetRootWindowMatching(gfx::Rect(0, 0, 1, 1)));
334 
335   // Empty rect.
336   EXPECT_EQ(root_windows[1],
337             wm::GetRootWindowMatching(gfx::Rect(-400, 100, 0, 0)));
338   EXPECT_EQ(root_windows[0],
339             wm::GetRootWindowMatching(gfx::Rect(100, 100, 0, 0)));
340 
341   // Out of range rect should return the primary root window.
342   EXPECT_EQ(root_windows[0],
343             wm::GetRootWindowMatching(gfx::Rect(-600, -300, 50, 50)));
344   EXPECT_EQ(root_windows[0],
345             wm::GetRootWindowMatching(gfx::Rect(0, 1000, 50, 50)));
346 }
347 
TEST_F(ExtendedDesktopTest,Capture)348 TEST_F(ExtendedDesktopTest, Capture) {
349   if (!SupportsMultipleDisplays())
350     return;
351 
352   UpdateDisplay("1000x600,600x400");
353   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
354 
355   aura::test::EventCountDelegate r1_d1;
356   aura::test::EventCountDelegate r1_d2;
357   aura::test::EventCountDelegate r2_d1;
358 
359   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
360       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
361   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
362       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
363   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
364       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
365 
366   r1_w1->SetCapture();
367 
368   EXPECT_EQ(r1_w1.get(),
369             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
370 
371   aura::test::EventGenerator& generator = GetEventGenerator();
372   generator.MoveMouseToCenterOf(r2_w1.get());
373   // |r1_w1| will receive the events because it has capture.
374   EXPECT_EQ("1 1 0", r1_d1.GetMouseMotionCountsAndReset());
375   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
376   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
377 
378   generator.ClickLeftButton();
379   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
380   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
381   // The mouse is outside. On chromeos, the mouse is warped to the
382   // dest root window, but it's not implemented on Win yet, so
383   // no mouse move event on Win.
384   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
385   EXPECT_EQ("1 1", r1_d1.GetMouseButtonCountsAndReset());
386 
387   generator.MoveMouseTo(15, 15);
388   EXPECT_EQ("0 1 0", r1_d1.GetMouseMotionCountsAndReset());
389   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
390 
391   r1_w2->SetCapture();
392   EXPECT_EQ(r1_w2.get(),
393             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
394   generator.MoveMouseBy(10, 10);
395   // |r1_w2| has the capture. So it will receive the mouse-move event.
396   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
397   EXPECT_EQ("0 1 0", r1_d2.GetMouseMotionCountsAndReset());
398   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
399 
400   generator.ClickLeftButton();
401   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
402   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
403   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
404   EXPECT_EQ("1 1", r1_d2.GetMouseButtonCountsAndReset());
405 
406   r1_w2->ReleaseCapture();
407   EXPECT_EQ(NULL, aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
408 
409   generator.MoveMouseToCenterOf(r2_w1.get());
410   generator.ClickLeftButton();
411   EXPECT_EQ("1 1 0", r2_d1.GetMouseMotionCountsAndReset());
412   EXPECT_EQ("1 1", r2_d1.GetMouseButtonCountsAndReset());
413   // Make sure the mouse_moved_handler_ is properly reset.
414   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
415   EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset());
416 }
417 
TEST_F(ExtendedDesktopTest,MoveWindow)418 TEST_F(ExtendedDesktopTest, MoveWindow) {
419   if (!SupportsMultipleDisplays())
420     return;
421 
422   UpdateDisplay("1000x600,600x400");
423   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
424   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
425 
426   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
427 
428   d1->SetBounds(gfx::Rect(1010, 10, 100, 100));
429   EXPECT_EQ("1010,10 100x100",
430             d1->GetWindowBoundsInScreen().ToString());
431 
432   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
433 
434   d1->SetBounds(gfx::Rect(10, 10, 100, 100));
435   EXPECT_EQ("10,10 100x100",
436             d1->GetWindowBoundsInScreen().ToString());
437 
438   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
439 
440   // Make sure the bounds which doesn't fit to the root window
441   // works correctly.
442   d1->SetBounds(gfx::Rect(1560, 30, 100, 100));
443   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
444   EXPECT_EQ("1560,30 100x100",
445             d1->GetWindowBoundsInScreen().ToString());
446 
447   // Setting outside of root windows will be moved to primary root window.
448   // TODO(oshima): This one probably should pick the closest root window.
449   d1->SetBounds(gfx::Rect(200, 10, 100, 100));
450   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
451 }
452 
453 // Verifies if the mouse event arrives to the window even when the window
454 // moves to another root in a pre-target handler.  See: crbug.com/157583
TEST_F(ExtendedDesktopTest,MoveWindowByMouseClick)455 TEST_F(ExtendedDesktopTest, MoveWindowByMouseClick) {
456   if (!SupportsMultipleDisplays())
457     return;
458 
459   UpdateDisplay("1000x600,600x400");
460 
461   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
462   aura::test::EventCountDelegate delegate;
463   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
464       &delegate, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
465   MoveWindowByClickEventHandler event_handler(window.get());
466   window->AddPreTargetHandler(&event_handler);
467 
468   aura::test::EventGenerator& event_generator(GetEventGenerator());
469 
470   event_generator.MoveMouseToCenterOf(window.get());
471   event_generator.ClickLeftButton();
472   // Both mouse pressed and released arrive at the window and its delegate.
473   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
474   // Also event_handler moves the window to another root at mouse release.
475   EXPECT_EQ(root_windows[1], window->GetRootWindow());
476 }
477 
TEST_F(ExtendedDesktopTest,MoveWindowToDisplay)478 TEST_F(ExtendedDesktopTest, MoveWindowToDisplay) {
479   if (!SupportsMultipleDisplays())
480     return;
481 
482   UpdateDisplay("1000x1000,1000x1000");
483   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
484 
485   gfx::Display display0 = Shell::GetScreen()->GetDisplayMatching(
486       root_windows[0]->GetBoundsInScreen());
487   gfx::Display display1 = Shell::GetScreen()->GetDisplayMatching(
488       root_windows[1]->GetBoundsInScreen());
489   EXPECT_NE(display0.id(), display1.id());
490 
491   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 1000, 100));
492   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
493 
494   // Move the window where the window spans both root windows. Since the second
495   // parameter is |display1|, the window should be shown on the secondary root.
496   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
497                                            display1);
498   EXPECT_EQ("500,10 1000x100",
499             d1->GetWindowBoundsInScreen().ToString());
500   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
501 
502   // Move to the primary root.
503   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
504                                            display0);
505   EXPECT_EQ("500,10 1000x100",
506             d1->GetWindowBoundsInScreen().ToString());
507   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
508 }
509 
TEST_F(ExtendedDesktopTest,MoveWindowWithTransient)510 TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) {
511   if (!SupportsMultipleDisplays())
512     return;
513 
514   UpdateDisplay("1000x600,600x400");
515   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
516   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
517   views::Widget* w1_t1 = CreateTestWidgetWithParent(
518       w1, gfx::Rect(50, 50, 50, 50), false /* transient */);
519   // Transient child of the transient child.
520   views::Widget* w1_t11 = CreateTestWidgetWithParent(
521       w1_t1, gfx::Rect(1200, 70, 35, 35), false /* transient */);
522 
523   views::Widget* w11 = CreateTestWidgetWithParent(
524       w1, gfx::Rect(10, 10, 40, 40), true /* child */);
525   views::Widget* w11_t1 = CreateTestWidgetWithParent(
526       w1, gfx::Rect(1300, 100, 80, 80), false /* transient */);
527 
528   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
529   EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow());
530   EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow());
531   EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow());
532   EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow());
533   EXPECT_EQ("50,50 50x50",
534             w1_t1->GetWindowBoundsInScreen().ToString());
535   EXPECT_EQ("1200,70 35x35",
536             w1_t11->GetWindowBoundsInScreen().ToString());
537   EXPECT_EQ("20,20 40x40",
538             w11->GetWindowBoundsInScreen().ToString());
539   EXPECT_EQ("1300,100 80x80",
540             w11_t1->GetWindowBoundsInScreen().ToString());
541 
542   w1->SetBounds(gfx::Rect(1100,10,100,100));
543 
544   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
545   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
546   EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow());
547   EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow());
548   EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow());
549 
550   EXPECT_EQ("1110,20 40x40",
551             w11->GetWindowBoundsInScreen().ToString());
552   // Transient window's screen bounds stays the same.
553   EXPECT_EQ("50,50 50x50",
554             w1_t1->GetWindowBoundsInScreen().ToString());
555   EXPECT_EQ("1200,70 35x35",
556             w1_t11->GetWindowBoundsInScreen().ToString());
557   EXPECT_EQ("1300,100 80x80",
558             w11_t1->GetWindowBoundsInScreen().ToString());
559 
560   // Transient window doesn't move between root window unless
561   // its transient parent moves.
562   w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50));
563   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
564   EXPECT_EQ("10,50 50x50",
565             w1_t1->GetWindowBoundsInScreen().ToString());
566 }
567 
568 // Test if the Window::ConvertPointToTarget works across root windows.
569 // TODO(oshima): Move multiple display suport and this test to aura.
TEST_F(ExtendedDesktopTest,ConvertPoint)570 TEST_F(ExtendedDesktopTest, ConvertPoint) {
571   if (!SupportsMultipleDisplays())
572     return;
573   gfx::Screen* screen = Shell::GetScreen();
574   UpdateDisplay("1000x600,600x400");
575   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
576   gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
577   EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
578   gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
579   EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
580 
581   aura::Window* d1 =
582       CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
583   aura::Window* d2 =
584       CreateTestWidget(gfx::Rect(1020, 20, 100, 100))->GetNativeView();
585   EXPECT_EQ(root_windows[0], d1->GetRootWindow());
586   EXPECT_EQ(root_windows[1], d2->GetRootWindow());
587 
588   // Convert point in the Root2's window to the Root1's window Coord.
589   gfx::Point p(0, 0);
590   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
591   EXPECT_EQ("1000,0", p.ToString());
592   p.SetPoint(0, 0);
593   aura::Window::ConvertPointToTarget(d2, d1, &p);
594   EXPECT_EQ("1010,10", p.ToString());
595 
596   // Convert point in the Root1's window to the Root2's window Coord.
597   p.SetPoint(0, 0);
598   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
599   EXPECT_EQ("-1000,0", p.ToString());
600   p.SetPoint(0, 0);
601   aura::Window::ConvertPointToTarget(d1, d2, &p);
602   EXPECT_EQ("-1010,-10", p.ToString());
603 
604   // Move the 2nd display to the bottom and test again.
605   SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
606 
607   display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
608   EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
609 
610   // Convert point in Root2's window to Root1's window Coord.
611   p.SetPoint(0, 0);
612   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
613   EXPECT_EQ("0,600", p.ToString());
614   p.SetPoint(0, 0);
615   aura::Window::ConvertPointToTarget(d2, d1, &p);
616   EXPECT_EQ("10,610", p.ToString());
617 
618   // Convert point in Root1's window to Root2's window Coord.
619   p.SetPoint(0, 0);
620   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
621   EXPECT_EQ("0,-600", p.ToString());
622   p.SetPoint(0, 0);
623   aura::Window::ConvertPointToTarget(d1, d2, &p);
624   EXPECT_EQ("-10,-610", p.ToString());
625 }
626 
TEST_F(ExtendedDesktopTest,OpenSystemTray)627 TEST_F(ExtendedDesktopTest, OpenSystemTray) {
628   if (!SupportsMultipleDisplays())
629     return;
630 
631   UpdateDisplay("500x600,600x400");
632   SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
633   ASSERT_FALSE(tray->HasSystemBubble());
634 
635   aura::test::EventGenerator& event_generator(GetEventGenerator());
636 
637   // Opens the tray by a dummy click event and makes sure that adding/removing
638   // displays doesn't break anything.
639   event_generator.MoveMouseToCenterOf(tray->GetWidget()->GetNativeWindow());
640   event_generator.ClickLeftButton();
641   EXPECT_TRUE(tray->HasSystemBubble());
642 
643   UpdateDisplay("500x600");
644   EXPECT_TRUE(tray->HasSystemBubble());
645   UpdateDisplay("500x600,600x400");
646   EXPECT_TRUE(tray->HasSystemBubble());
647 
648   // Closes the tray and again makes sure that adding/removing displays doesn't
649   // break anything.
650   event_generator.ClickLeftButton();
651   RunAllPendingInMessageLoop();
652 
653   EXPECT_FALSE(tray->HasSystemBubble());
654 
655   UpdateDisplay("500x600");
656   EXPECT_FALSE(tray->HasSystemBubble());
657   UpdateDisplay("500x600,600x400");
658   EXPECT_FALSE(tray->HasSystemBubble());
659 }
660 
TEST_F(ExtendedDesktopTest,StayInSameRootWindow)661 TEST_F(ExtendedDesktopTest, StayInSameRootWindow) {
662   if (!SupportsMultipleDisplays())
663     return;
664 
665   UpdateDisplay("100x100,200x200");
666   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
667   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 50, 50));
668   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
669   w1->SetBounds(gfx::Rect(150, 10, 50, 50));
670   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
671 
672   // The widget stays in the same root if kStayInSameRootWindowKey is set to
673   // true.
674   w1->GetNativeView()->SetProperty(kStayInSameRootWindowKey, true);
675   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
676   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
677 
678   // The widget should now move to the 1st root window without the property.
679   w1->GetNativeView()->ClearProperty(kStayInSameRootWindowKey);
680   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
681   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
682 
683   // a window in SettingsBubbleContainer and StatusContainer should
684   // not move to another root window regardles of the bounds specified.
685   aura::Window* settings_bubble_container =
686       Shell::GetPrimaryRootWindowController()->GetContainer(
687           kShellWindowId_SettingBubbleContainer);
688   aura::Window* window = aura::test::CreateTestWindowWithId(
689       100, settings_bubble_container);
690   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
691                             ScreenUtil::GetSecondaryDisplay());
692   EXPECT_EQ(root_windows[0], window->GetRootWindow());
693 
694   aura::Window* status_container =
695       Shell::GetPrimaryRootWindowController()->GetContainer(
696           kShellWindowId_StatusContainer);
697   window = aura::test::CreateTestWindowWithId(100, status_container);
698   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
699                             ScreenUtil::GetSecondaryDisplay());
700   EXPECT_EQ(root_windows[0], window->GetRootWindow());
701 }
702 
TEST_F(ExtendedDesktopTest,KeyEventsOnLockScreen)703 TEST_F(ExtendedDesktopTest, KeyEventsOnLockScreen) {
704   if (!SupportsMultipleDisplays())
705     return;
706 
707   UpdateDisplay("100x100,200x200");
708   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
709 
710   // Create normal windows on both displays.
711   views::Widget* widget1 = CreateTestWidget(
712       Shell::GetScreen()->GetPrimaryDisplay().bounds());
713   widget1->Show();
714   EXPECT_EQ(root_windows[0], widget1->GetNativeView()->GetRootWindow());
715   views::Widget* widget2 = CreateTestWidget(
716       ScreenUtil::GetSecondaryDisplay().bounds());
717   widget2->Show();
718   EXPECT_EQ(root_windows[1], widget2->GetNativeView()->GetRootWindow());
719 
720   // Create a LockScreen window.
721   views::Widget* lock_widget = CreateTestWidget(
722       Shell::GetScreen()->GetPrimaryDisplay().bounds());
723   views::Textfield* textfield = new views::Textfield;
724   lock_widget->client_view()->AddChildView(textfield);
725 
726   ash::Shell::GetContainer(Shell::GetPrimaryRootWindow(),
727                            ash::kShellWindowId_LockScreenContainer)
728       ->AddChild(lock_widget->GetNativeView());
729   lock_widget->Show();
730   textfield->RequestFocus();
731 
732   aura::client::FocusClient* focus_client =
733       aura::client::GetFocusClient(root_windows[0]);
734   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
735 
736   // The lock window should get events on both root windows.
737   aura::test::EventGenerator& event_generator(GetEventGenerator());
738 
739   event_generator.set_current_host(root_windows[0]->GetHost());
740   event_generator.PressKey(ui::VKEY_A, 0);
741   event_generator.ReleaseKey(ui::VKEY_A, 0);
742   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
743   EXPECT_EQ("a", base::UTF16ToASCII(textfield->text()));
744 
745   event_generator.set_current_host(root_windows[1]->GetHost());
746   event_generator.PressKey(ui::VKEY_B, 0);
747   event_generator.ReleaseKey(ui::VKEY_B, 0);
748   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
749   EXPECT_EQ("ab", base::UTF16ToASCII(textfield->text()));
750 
751   // Deleting 2nd display. The lock window still should get the events.
752   UpdateDisplay("100x100");
753   event_generator.PressKey(ui::VKEY_C, 0);
754   event_generator.ReleaseKey(ui::VKEY_C, 0);
755   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
756   EXPECT_EQ("abc", base::UTF16ToASCII(textfield->text()));
757 
758   // Creating 2nd display again, and lock window still should get events
759   // on both root windows.
760   UpdateDisplay("100x100,200x200");
761   root_windows = Shell::GetAllRootWindows();
762   event_generator.set_current_host(root_windows[0]->GetHost());
763   event_generator.PressKey(ui::VKEY_D, 0);
764   event_generator.ReleaseKey(ui::VKEY_D, 0);
765   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
766   EXPECT_EQ("abcd", base::UTF16ToASCII(textfield->text()));
767 
768   event_generator.set_current_host(root_windows[1]->GetHost());
769   event_generator.PressKey(ui::VKEY_E, 0);
770   event_generator.ReleaseKey(ui::VKEY_E, 0);
771   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
772   EXPECT_EQ("abcde", base::UTF16ToASCII(textfield->text()));
773 }
774 
TEST_F(ExtendedDesktopTest,PassiveGrab)775 TEST_F(ExtendedDesktopTest, PassiveGrab) {
776   if (!SupportsMultipleDisplays())
777     return;
778 
779   EventLocationRecordingEventHandler event_handler;
780   ash::Shell::GetInstance()->AddPreTargetHandler(&event_handler);
781 
782   UpdateDisplay("300x300,200x200");
783 
784   views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
785   widget->Show();
786   ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
787 
788   aura::test::EventGenerator& generator(GetEventGenerator());
789   generator.MoveMouseTo(150, 150);
790   EXPECT_EQ("100,100 150,150", event_handler.GetLocationsAndReset());
791 
792   generator.PressLeftButton();
793   generator.MoveMouseTo(400, 150);
794 
795   EXPECT_EQ("350,100 400,150", event_handler.GetLocationsAndReset());
796 
797   generator.ReleaseLeftButton();
798   EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
799 
800   generator.MoveMouseTo(400, 150);
801   EXPECT_EQ("100,150 100,150", event_handler.GetLocationsAndReset());
802 
803   ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
804 }
805 
806 }  // namespace ash
807