• 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/test_windows.h"
21 #include "ui/aura/test/window_test_api.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_event_dispatcher.h"
24 #include "ui/base/cursor/cursor.h"
25 #include "ui/events/event_handler.h"
26 #include "ui/events/test/event_generator.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 class EventLocationHandler : public ui::EventHandler {
121  public:
EventLocationHandler()122   EventLocationHandler() {}
~EventLocationHandler()123   virtual ~EventLocationHandler() {}
124 
press_location() const125   const gfx::Point& press_location() const { return press_location_; }
release_location() const126   const gfx::Point& release_location() const { return release_location_; }
127 
128  private:
129   // ui::EventHandler:
OnMouseEvent(ui::MouseEvent * event)130   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
131     if (event->type() == ui::ET_MOUSE_PRESSED)
132       press_location_ = event->location();
133     else if (event->type() == ui::ET_MOUSE_RELEASED)
134       release_location_ = event->location();
135   }
136 
137   gfx::Point press_location_;
138   gfx::Point release_location_;
139 
140   DISALLOW_COPY_AND_ASSIGN(EventLocationHandler);
141 };
142 
143 }  // namespace
144 
145 class ExtendedDesktopTest : public test::AshTestBase {
146  public:
CreateTestWidget(const gfx::Rect & bounds)147   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
148     return CreateTestWidgetWithParentAndContext(
149         NULL, CurrentContext(), bounds, false);
150   }
151 
CreateTestWidgetWithParent(views::Widget * parent,const gfx::Rect & bounds,bool child)152   views::Widget* CreateTestWidgetWithParent(views::Widget* parent,
153                                             const gfx::Rect& bounds,
154                                             bool child) {
155     CHECK(parent);
156     return CreateTestWidgetWithParentAndContext(parent, NULL, bounds, child);
157   }
158 
CreateTestWidgetWithParentAndContext(views::Widget * parent,gfx::NativeView context,const gfx::Rect & bounds,bool child)159   views::Widget* CreateTestWidgetWithParentAndContext(views::Widget* parent,
160                                                       gfx::NativeView context,
161                                                       const gfx::Rect& bounds,
162                                                       bool child) {
163     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
164     if (parent)
165       params.parent = parent->GetNativeView();
166     params.context = context;
167     params.bounds = bounds;
168     params.child = child;
169     views::Widget* widget = new views::Widget;
170     widget->Init(params);
171     widget->Show();
172     return widget;
173   }
174 };
175 
176 // Test conditions that root windows in extended desktop mode
177 // must satisfy.
TEST_F(ExtendedDesktopTest,Basic)178 TEST_F(ExtendedDesktopTest, Basic) {
179   if (!SupportsMultipleDisplays())
180     return;
181 
182   UpdateDisplay("1000x600,600x400");
183   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
184 
185   // All root windows must have the root window controller.
186   ASSERT_EQ(2U, root_windows.size());
187   for (aura::Window::Windows::const_iterator iter = root_windows.begin();
188        iter != root_windows.end(); ++iter) {
189     EXPECT_TRUE(GetRootWindowController(*iter) != NULL);
190   }
191   // Make sure root windows share the same controllers.
192   EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
193             aura::client::GetFocusClient(root_windows[1]));
194   EXPECT_EQ(aura::client::GetActivationClient(root_windows[0]),
195             aura::client::GetActivationClient(root_windows[1]));
196   EXPECT_EQ(aura::client::GetCaptureClient(root_windows[0]),
197             aura::client::GetCaptureClient(root_windows[1]));
198 }
199 
TEST_F(ExtendedDesktopTest,Activation)200 TEST_F(ExtendedDesktopTest, Activation) {
201   if (!SupportsMultipleDisplays())
202     return;
203 
204   UpdateDisplay("1000x600,600x400");
205   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
206 
207   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
208   views::Widget* widget_on_2nd =
209       CreateTestWidget(gfx::Rect(1200, 10, 100, 100));
210   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
211   EXPECT_EQ(root_windows[1], widget_on_2nd->GetNativeView()->GetRootWindow());
212 
213   EXPECT_EQ(widget_on_2nd->GetNativeView(),
214             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
215   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
216 
217   ui::test::EventGenerator& event_generator(GetEventGenerator());
218   // Clicking a window changes the active window and active root window.
219   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
220   event_generator.ClickLeftButton();
221 
222   EXPECT_EQ(widget_on_1st->GetNativeView(),
223             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
224   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
225 
226   event_generator.MoveMouseToCenterOf(widget_on_2nd->GetNativeView());
227   event_generator.ClickLeftButton();
228 
229   EXPECT_EQ(widget_on_2nd->GetNativeView(),
230             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
231   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
232 }
233 
TEST_F(ExtendedDesktopTest,SystemModal)234 TEST_F(ExtendedDesktopTest, SystemModal) {
235   if (!SupportsMultipleDisplays())
236     return;
237 
238   UpdateDisplay("1000x600,600x400");
239   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
240 
241   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
242   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
243   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
244   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
245 
246   // Open system modal. Make sure it's on 2nd root window and active.
247   views::Widget* modal_widget = views::Widget::CreateWindowWithContextAndBounds(
248       new ModalWidgetDelegate(),
249       CurrentContext(),
250       gfx::Rect(1200, 100, 100, 100));
251   modal_widget->Show();
252   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
253   EXPECT_EQ(root_windows[1], modal_widget->GetNativeView()->GetRootWindow());
254   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
255 
256   ui::test::EventGenerator& event_generator(GetEventGenerator());
257 
258   // Clicking a widget on widget_on_1st display should not change activation.
259   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
260   event_generator.ClickLeftButton();
261   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
262   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
263 
264   // Close system modal and so clicking a widget should work now.
265   modal_widget->Close();
266   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
267   event_generator.ClickLeftButton();
268   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
269   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
270 }
271 
TEST_F(ExtendedDesktopTest,TestCursor)272 TEST_F(ExtendedDesktopTest, TestCursor) {
273   if (!SupportsMultipleDisplays())
274     return;
275 
276   UpdateDisplay("1000x600,600x400");
277   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
278   aura::WindowTreeHost* host0 = root_windows[0]->GetHost();
279   aura::WindowTreeHost* host1 = root_windows[1]->GetHost();
280   EXPECT_EQ(ui::kCursorPointer, host0->last_cursor().native_type());
281   EXPECT_EQ(ui::kCursorPointer, host1->last_cursor().native_type());
282   Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
283   EXPECT_EQ(ui::kCursorCopy, host0->last_cursor().native_type());
284   EXPECT_EQ(ui::kCursorCopy, host1->last_cursor().native_type());
285 }
286 
TEST_F(ExtendedDesktopTest,TestCursorLocation)287 TEST_F(ExtendedDesktopTest, TestCursorLocation) {
288   if (!SupportsMultipleDisplays())
289     return;
290 
291   UpdateDisplay("1000x600,600x400");
292   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
293   aura::test::WindowTestApi root_window0_test_api(root_windows[0]);
294   aura::test::WindowTestApi root_window1_test_api(root_windows[1]);
295 
296   root_windows[0]->MoveCursorTo(gfx::Point(10, 10));
297   EXPECT_EQ("10,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
298   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
299   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
300   root_windows[1]->MoveCursorTo(gfx::Point(10, 20));
301   EXPECT_EQ("1010,20", Shell::GetScreen()->GetCursorScreenPoint().ToString());
302   EXPECT_FALSE(root_window0_test_api.ContainsMouse());
303   EXPECT_TRUE(root_window1_test_api.ContainsMouse());
304   root_windows[0]->MoveCursorTo(gfx::Point(20, 10));
305   EXPECT_EQ("20,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
306   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
307   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
308 }
309 
TEST_F(ExtendedDesktopTest,GetRootWindowAt)310 TEST_F(ExtendedDesktopTest, GetRootWindowAt) {
311   if (!SupportsMultipleDisplays())
312     return;
313 
314   UpdateDisplay("700x500,500x500");
315   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
316   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
317 
318   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100)));
319   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-1, 100)));
320   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 300)));
321   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(700, 300)));
322 
323   // Zero origin.
324   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 0)));
325 
326   // Out of range point should return the nearest root window
327   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-600, 0)));
328   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(701, 100)));
329 }
330 
TEST_F(ExtendedDesktopTest,GetRootWindowMatching)331 TEST_F(ExtendedDesktopTest, GetRootWindowMatching) {
332   if (!SupportsMultipleDisplays())
333     return;
334 
335   UpdateDisplay("700x500,500x500");
336   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
337 
338   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
339 
340   // Containing rect.
341   EXPECT_EQ(root_windows[1],
342             wm::GetRootWindowMatching(gfx::Rect(-300, 10, 50, 50)));
343   EXPECT_EQ(root_windows[0],
344             wm::GetRootWindowMatching(gfx::Rect(100, 10, 50, 50)));
345 
346   // Intersecting rect.
347   EXPECT_EQ(root_windows[1],
348             wm::GetRootWindowMatching(gfx::Rect(-200, 0, 300, 300)));
349   EXPECT_EQ(root_windows[0],
350             wm::GetRootWindowMatching(gfx::Rect(-100, 0, 300, 300)));
351 
352   // Zero origin.
353   EXPECT_EQ(root_windows[0],
354             wm::GetRootWindowMatching(gfx::Rect(0, 0, 0, 0)));
355   EXPECT_EQ(root_windows[0],
356             wm::GetRootWindowMatching(gfx::Rect(0, 0, 1, 1)));
357 
358   // Empty rect.
359   EXPECT_EQ(root_windows[1],
360             wm::GetRootWindowMatching(gfx::Rect(-400, 100, 0, 0)));
361   EXPECT_EQ(root_windows[0],
362             wm::GetRootWindowMatching(gfx::Rect(100, 100, 0, 0)));
363 
364   // Out of range rect should return the primary root window.
365   EXPECT_EQ(root_windows[0],
366             wm::GetRootWindowMatching(gfx::Rect(-600, -300, 50, 50)));
367   EXPECT_EQ(root_windows[0],
368             wm::GetRootWindowMatching(gfx::Rect(0, 1000, 50, 50)));
369 }
370 
TEST_F(ExtendedDesktopTest,Capture)371 TEST_F(ExtendedDesktopTest, Capture) {
372   if (!SupportsMultipleDisplays())
373     return;
374 
375   UpdateDisplay("1000x600,600x400");
376   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
377 
378   aura::test::EventCountDelegate r1_d1;
379   aura::test::EventCountDelegate r1_d2;
380   aura::test::EventCountDelegate r2_d1;
381 
382   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
383       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
384   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
385       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
386   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
387       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
388 
389   r1_w1->SetCapture();
390 
391   EXPECT_EQ(r1_w1.get(),
392             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
393 
394   ui::test::EventGenerator& generator = GetEventGenerator();
395   generator.MoveMouseToCenterOf(r2_w1.get());
396   // |r1_w1| will receive the events because it has capture.
397   EXPECT_EQ("1 1 0", r1_d1.GetMouseMotionCountsAndReset());
398   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
399   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
400 
401   generator.ClickLeftButton();
402   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
403   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
404   // The mouse is outside. On chromeos, the mouse is warped to the
405   // dest root window, but it's not implemented on Win yet, so
406   // no mouse move event on Win.
407   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
408   EXPECT_EQ("1 1", r1_d1.GetMouseButtonCountsAndReset());
409 
410   generator.MoveMouseTo(15, 15);
411   EXPECT_EQ("0 1 0", r1_d1.GetMouseMotionCountsAndReset());
412   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
413 
414   r1_w2->SetCapture();
415   EXPECT_EQ(r1_w2.get(),
416             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
417   generator.MoveMouseBy(10, 10);
418   // |r1_w2| has the capture. So it will receive the mouse-move event.
419   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
420   EXPECT_EQ("0 1 0", r1_d2.GetMouseMotionCountsAndReset());
421   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
422 
423   generator.ClickLeftButton();
424   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
425   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
426   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
427   EXPECT_EQ("1 1", r1_d2.GetMouseButtonCountsAndReset());
428 
429   r1_w2->ReleaseCapture();
430   EXPECT_EQ(NULL, aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
431 
432   generator.MoveMouseToCenterOf(r2_w1.get());
433   generator.ClickLeftButton();
434   EXPECT_EQ("1 1 0", r2_d1.GetMouseMotionCountsAndReset());
435   EXPECT_EQ("1 1", r2_d1.GetMouseButtonCountsAndReset());
436   // Make sure the mouse_moved_handler_ is properly reset.
437   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
438   EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset());
439 }
440 
TEST_F(ExtendedDesktopTest,CaptureEventLocation)441 TEST_F(ExtendedDesktopTest, CaptureEventLocation) {
442   if (!SupportsMultipleDisplays())
443     return;
444 
445   UpdateDisplay("1000x600,600x400");
446   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
447 
448   aura::test::EventCountDelegate r1_d1;
449   aura::test::EventCountDelegate r1_d2;
450   aura::test::EventCountDelegate r2_d1;
451 
452   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
453       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
454   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
455       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
456   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
457       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
458 
459   r1_w1->SetCapture();
460 
461   ui::test::EventGenerator& generator = GetEventGenerator();
462   generator.MoveMouseToCenterOf(r2_w1.get());
463   EXPECT_EQ(gfx::Point(1060, 60).ToString(),
464             generator.current_location().ToString());
465 
466   EventLocationHandler location_handler;
467   r1_w1->AddPreTargetHandler(&location_handler);
468   generator.ClickLeftButton();
469   r1_w1->RemovePreTargetHandler(&location_handler);
470   EXPECT_EQ(gfx::Point(1050, 50).ToString(),
471             location_handler.press_location().ToString());
472   EXPECT_EQ(gfx::Point(1050, 50).ToString(),
473             location_handler.release_location().ToString());
474 }
475 
TEST_F(ExtendedDesktopTest,CaptureEventLocationHighDPI)476 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI) {
477   if (!SupportsMultipleDisplays())
478     return;
479 
480   UpdateDisplay("1000x600*2,600x400");
481   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
482 
483   aura::test::EventCountDelegate r1_d1;
484   aura::test::EventCountDelegate r1_d2;
485   aura::test::EventCountDelegate r2_d1;
486 
487   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
488       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
489   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
490       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
491   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
492       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
493 
494   r1_w1->SetCapture();
495 
496   ui::test::EventGenerator& generator = GetEventGenerator();
497   generator.MoveMouseToCenterOf(r2_w1.get());
498   EXPECT_EQ(gfx::Point(560, 60).ToString(),
499             generator.current_location().ToString());
500 
501   EventLocationHandler location_handler;
502   r1_w1->AddPreTargetHandler(&location_handler);
503   generator.ClickLeftButton();
504   r1_w1->RemovePreTargetHandler(&location_handler);
505   EXPECT_EQ(gfx::Point(550, 50).ToString(),
506             location_handler.press_location().ToString());
507   EXPECT_EQ(gfx::Point(550, 50).ToString(),
508             location_handler.release_location().ToString());
509 }
510 
TEST_F(ExtendedDesktopTest,CaptureEventLocationHighDPI_2)511 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI_2) {
512   if (!SupportsMultipleDisplays())
513     return;
514 
515   UpdateDisplay("1000x600,600x400*2");
516   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
517 
518   aura::test::EventCountDelegate r1_d1;
519   aura::test::EventCountDelegate r1_d2;
520   aura::test::EventCountDelegate r2_d1;
521 
522   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
523       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
524   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
525       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
526   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
527       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
528 
529   r1_w1->SetCapture();
530 
531   ui::test::EventGenerator& generator = GetEventGenerator();
532   generator.MoveMouseToCenterOf(r2_w1.get());
533   EXPECT_EQ(gfx::Point(1060, 60).ToString(),
534             generator.current_location().ToString());
535 
536   EventLocationHandler location_handler;
537   r1_w1->AddPreTargetHandler(&location_handler);
538   generator.ClickLeftButton();
539   r1_w1->RemovePreTargetHandler(&location_handler);
540   // Event-generator dispatches the event in the primary root-window's coord
541   // space. Since the location is (1060, 60), it goes to the secondary
542   // root-window as (30, 30) since the secondary root-window has a device scale
543   // factor of 2.
544   EXPECT_EQ(gfx::Point(1020, 20).ToString(),
545             location_handler.press_location().ToString());
546   EXPECT_EQ(gfx::Point(1020, 20).ToString(),
547             location_handler.release_location().ToString());
548 }
549 
TEST_F(ExtendedDesktopTest,MoveWindow)550 TEST_F(ExtendedDesktopTest, MoveWindow) {
551   if (!SupportsMultipleDisplays())
552     return;
553 
554   UpdateDisplay("1000x600,600x400");
555   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
556   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
557 
558   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
559 
560   d1->SetBounds(gfx::Rect(1010, 10, 100, 100));
561   EXPECT_EQ("1010,10 100x100",
562             d1->GetWindowBoundsInScreen().ToString());
563 
564   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
565 
566   d1->SetBounds(gfx::Rect(10, 10, 100, 100));
567   EXPECT_EQ("10,10 100x100",
568             d1->GetWindowBoundsInScreen().ToString());
569 
570   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
571 
572   // Make sure the bounds which doesn't fit to the root window
573   // works correctly.
574   d1->SetBounds(gfx::Rect(1560, 30, 100, 100));
575   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
576   EXPECT_EQ("1560,30 100x100",
577             d1->GetWindowBoundsInScreen().ToString());
578 
579   // Setting outside of root windows will be moved to primary root window.
580   // TODO(oshima): This one probably should pick the closest root window.
581   d1->SetBounds(gfx::Rect(200, 10, 100, 100));
582   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
583 }
584 
585 // Verifies if the mouse event arrives to the window even when the window
586 // moves to another root in a pre-target handler.  See: crbug.com/157583
TEST_F(ExtendedDesktopTest,MoveWindowByMouseClick)587 TEST_F(ExtendedDesktopTest, MoveWindowByMouseClick) {
588   if (!SupportsMultipleDisplays())
589     return;
590 
591   UpdateDisplay("1000x600,600x400");
592 
593   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
594   aura::test::EventCountDelegate delegate;
595   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
596       &delegate, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
597   MoveWindowByClickEventHandler event_handler(window.get());
598   window->AddPreTargetHandler(&event_handler);
599 
600   ui::test::EventGenerator& event_generator(GetEventGenerator());
601 
602   event_generator.MoveMouseToCenterOf(window.get());
603   event_generator.ClickLeftButton();
604   // Both mouse pressed and released arrive at the window and its delegate.
605   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
606   // Also event_handler moves the window to another root at mouse release.
607   EXPECT_EQ(root_windows[1], window->GetRootWindow());
608 }
609 
TEST_F(ExtendedDesktopTest,MoveWindowToDisplay)610 TEST_F(ExtendedDesktopTest, MoveWindowToDisplay) {
611   if (!SupportsMultipleDisplays())
612     return;
613 
614   UpdateDisplay("1000x1000,1000x1000");
615   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
616 
617   gfx::Display display0 = Shell::GetScreen()->GetDisplayMatching(
618       root_windows[0]->GetBoundsInScreen());
619   gfx::Display display1 = Shell::GetScreen()->GetDisplayMatching(
620       root_windows[1]->GetBoundsInScreen());
621   EXPECT_NE(display0.id(), display1.id());
622 
623   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 1000, 100));
624   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
625 
626   // Move the window where the window spans both root windows. Since the second
627   // parameter is |display1|, the window should be shown on the secondary root.
628   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
629                                            display1);
630   EXPECT_EQ("500,10 1000x100",
631             d1->GetWindowBoundsInScreen().ToString());
632   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
633 
634   // Move to the primary root.
635   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
636                                            display0);
637   EXPECT_EQ("500,10 1000x100",
638             d1->GetWindowBoundsInScreen().ToString());
639   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
640 }
641 
TEST_F(ExtendedDesktopTest,MoveWindowWithTransient)642 TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) {
643   if (!SupportsMultipleDisplays())
644     return;
645 
646   UpdateDisplay("1000x600,600x400");
647   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
648   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
649   views::Widget* w1_t1 = CreateTestWidgetWithParent(
650       w1, gfx::Rect(50, 50, 50, 50), false /* transient */);
651   // Transient child of the transient child.
652   views::Widget* w1_t11 = CreateTestWidgetWithParent(
653       w1_t1, gfx::Rect(1200, 70, 35, 35), false /* transient */);
654 
655   views::Widget* w11 = CreateTestWidgetWithParent(
656       w1, gfx::Rect(10, 10, 40, 40), true /* child */);
657   views::Widget* w11_t1 = CreateTestWidgetWithParent(
658       w1, gfx::Rect(1300, 100, 80, 80), false /* transient */);
659 
660   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
661   EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow());
662   EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow());
663   EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow());
664   EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow());
665   EXPECT_EQ("50,50 50x50",
666             w1_t1->GetWindowBoundsInScreen().ToString());
667   EXPECT_EQ("1200,70 35x35",
668             w1_t11->GetWindowBoundsInScreen().ToString());
669   EXPECT_EQ("20,20 40x40",
670             w11->GetWindowBoundsInScreen().ToString());
671   EXPECT_EQ("1300,100 80x80",
672             w11_t1->GetWindowBoundsInScreen().ToString());
673 
674   w1->SetBounds(gfx::Rect(1100, 10, 100, 100));
675 
676   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
677   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
678   EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow());
679   EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow());
680   EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow());
681 
682   EXPECT_EQ("1110,20 40x40",
683             w11->GetWindowBoundsInScreen().ToString());
684   // Transient window's screen bounds stays the same.
685   EXPECT_EQ("50,50 50x50",
686             w1_t1->GetWindowBoundsInScreen().ToString());
687   EXPECT_EQ("1200,70 35x35",
688             w1_t11->GetWindowBoundsInScreen().ToString());
689   EXPECT_EQ("1300,100 80x80",
690             w11_t1->GetWindowBoundsInScreen().ToString());
691 
692   // Transient window doesn't move between root window unless
693   // its transient parent moves.
694   w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50));
695   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
696   EXPECT_EQ("10,50 50x50",
697             w1_t1->GetWindowBoundsInScreen().ToString());
698 }
699 
700 // Test if the Window::ConvertPointToTarget works across root windows.
701 // TODO(oshima): Move multiple display suport and this test to aura.
TEST_F(ExtendedDesktopTest,ConvertPoint)702 TEST_F(ExtendedDesktopTest, ConvertPoint) {
703   if (!SupportsMultipleDisplays())
704     return;
705   gfx::Screen* screen = Shell::GetScreen();
706   UpdateDisplay("1000x600,600x400");
707   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
708   gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
709   EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
710   gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
711   EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
712 
713   aura::Window* d1 =
714       CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
715   aura::Window* d2 =
716       CreateTestWidget(gfx::Rect(1020, 20, 100, 100))->GetNativeView();
717   EXPECT_EQ(root_windows[0], d1->GetRootWindow());
718   EXPECT_EQ(root_windows[1], d2->GetRootWindow());
719 
720   // Convert point in the Root2's window to the Root1's window Coord.
721   gfx::Point p(0, 0);
722   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
723   EXPECT_EQ("1000,0", p.ToString());
724   p.SetPoint(0, 0);
725   aura::Window::ConvertPointToTarget(d2, d1, &p);
726   EXPECT_EQ("1010,10", p.ToString());
727 
728   // Convert point in the Root1's window to the Root2's window Coord.
729   p.SetPoint(0, 0);
730   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
731   EXPECT_EQ("-1000,0", p.ToString());
732   p.SetPoint(0, 0);
733   aura::Window::ConvertPointToTarget(d1, d2, &p);
734   EXPECT_EQ("-1010,-10", p.ToString());
735 
736   // Move the 2nd display to the bottom and test again.
737   SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
738 
739   display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
740   EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
741 
742   // Convert point in Root2's window to Root1's window Coord.
743   p.SetPoint(0, 0);
744   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
745   EXPECT_EQ("0,600", p.ToString());
746   p.SetPoint(0, 0);
747   aura::Window::ConvertPointToTarget(d2, d1, &p);
748   EXPECT_EQ("10,610", p.ToString());
749 
750   // Convert point in Root1's window to Root2's window Coord.
751   p.SetPoint(0, 0);
752   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
753   EXPECT_EQ("0,-600", p.ToString());
754   p.SetPoint(0, 0);
755   aura::Window::ConvertPointToTarget(d1, d2, &p);
756   EXPECT_EQ("-10,-610", p.ToString());
757 }
758 
TEST_F(ExtendedDesktopTest,OpenSystemTray)759 TEST_F(ExtendedDesktopTest, OpenSystemTray) {
760   if (!SupportsMultipleDisplays())
761     return;
762 
763   UpdateDisplay("500x600,600x400");
764   SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
765   ASSERT_FALSE(tray->HasSystemBubble());
766 
767   ui::test::EventGenerator& event_generator(GetEventGenerator());
768 
769   // Opens the tray by a dummy click event and makes sure that adding/removing
770   // displays doesn't break anything.
771   event_generator.MoveMouseToCenterOf(tray->GetWidget()->GetNativeWindow());
772   event_generator.ClickLeftButton();
773   EXPECT_TRUE(tray->HasSystemBubble());
774 
775   UpdateDisplay("500x600");
776   EXPECT_TRUE(tray->HasSystemBubble());
777   UpdateDisplay("500x600,600x400");
778   EXPECT_TRUE(tray->HasSystemBubble());
779 
780   // Closes the tray and again makes sure that adding/removing displays doesn't
781   // break anything.
782   event_generator.ClickLeftButton();
783   RunAllPendingInMessageLoop();
784 
785   EXPECT_FALSE(tray->HasSystemBubble());
786 
787   UpdateDisplay("500x600");
788   EXPECT_FALSE(tray->HasSystemBubble());
789   UpdateDisplay("500x600,600x400");
790   EXPECT_FALSE(tray->HasSystemBubble());
791 }
792 
TEST_F(ExtendedDesktopTest,StayInSameRootWindow)793 TEST_F(ExtendedDesktopTest, StayInSameRootWindow) {
794   if (!SupportsMultipleDisplays())
795     return;
796 
797   UpdateDisplay("100x100,200x200");
798   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
799   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 50, 50));
800   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
801   w1->SetBounds(gfx::Rect(150, 10, 50, 50));
802   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
803 
804   // The widget stays in the same root if kStayInSameRootWindowKey is set to
805   // true.
806   w1->GetNativeView()->SetProperty(kStayInSameRootWindowKey, true);
807   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
808   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
809 
810   // The widget should now move to the 1st root window without the property.
811   w1->GetNativeView()->ClearProperty(kStayInSameRootWindowKey);
812   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
813   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
814 
815   // a window in SettingsBubbleContainer and StatusContainer should
816   // not move to another root window regardles of the bounds specified.
817   aura::Window* settings_bubble_container =
818       Shell::GetPrimaryRootWindowController()->GetContainer(
819           kShellWindowId_SettingBubbleContainer);
820   aura::Window* window = aura::test::CreateTestWindowWithId(
821       100, settings_bubble_container);
822   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
823                             ScreenUtil::GetSecondaryDisplay());
824   EXPECT_EQ(root_windows[0], window->GetRootWindow());
825 
826   aura::Window* status_container =
827       Shell::GetPrimaryRootWindowController()->GetContainer(
828           kShellWindowId_StatusContainer);
829   window = aura::test::CreateTestWindowWithId(100, status_container);
830   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
831                             ScreenUtil::GetSecondaryDisplay());
832   EXPECT_EQ(root_windows[0], window->GetRootWindow());
833 }
834 
TEST_F(ExtendedDesktopTest,KeyEventsOnLockScreen)835 TEST_F(ExtendedDesktopTest, KeyEventsOnLockScreen) {
836   if (!SupportsMultipleDisplays())
837     return;
838 
839   UpdateDisplay("100x100,200x200");
840   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
841 
842   // Create normal windows on both displays.
843   views::Widget* widget1 = CreateTestWidget(
844       Shell::GetScreen()->GetPrimaryDisplay().bounds());
845   widget1->Show();
846   EXPECT_EQ(root_windows[0], widget1->GetNativeView()->GetRootWindow());
847   views::Widget* widget2 = CreateTestWidget(
848       ScreenUtil::GetSecondaryDisplay().bounds());
849   widget2->Show();
850   EXPECT_EQ(root_windows[1], widget2->GetNativeView()->GetRootWindow());
851 
852   // Create a LockScreen window.
853   views::Widget* lock_widget = CreateTestWidget(
854       Shell::GetScreen()->GetPrimaryDisplay().bounds());
855   views::Textfield* textfield = new views::Textfield;
856   lock_widget->client_view()->AddChildView(textfield);
857 
858   ash::Shell::GetContainer(Shell::GetPrimaryRootWindow(),
859                            ash::kShellWindowId_LockScreenContainer)
860       ->AddChild(lock_widget->GetNativeView());
861   lock_widget->Show();
862   textfield->RequestFocus();
863 
864   aura::client::FocusClient* focus_client =
865       aura::client::GetFocusClient(root_windows[0]);
866   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
867 
868   // The lock window should get events on both root windows.
869   ui::test::EventGenerator& event_generator(GetEventGenerator());
870 
871   event_generator.set_current_target(root_windows[0]);
872   event_generator.PressKey(ui::VKEY_A, 0);
873   event_generator.ReleaseKey(ui::VKEY_A, 0);
874   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
875   EXPECT_EQ("a", base::UTF16ToASCII(textfield->text()));
876 
877   event_generator.set_current_target(root_windows[1]);
878   event_generator.PressKey(ui::VKEY_B, 0);
879   event_generator.ReleaseKey(ui::VKEY_B, 0);
880   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
881   EXPECT_EQ("ab", base::UTF16ToASCII(textfield->text()));
882 
883   // Deleting 2nd display. The lock window still should get the events.
884   UpdateDisplay("100x100");
885   event_generator.PressKey(ui::VKEY_C, 0);
886   event_generator.ReleaseKey(ui::VKEY_C, 0);
887   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
888   EXPECT_EQ("abc", base::UTF16ToASCII(textfield->text()));
889 
890   // Creating 2nd display again, and lock window still should get events
891   // on both root windows.
892   UpdateDisplay("100x100,200x200");
893   root_windows = Shell::GetAllRootWindows();
894   event_generator.set_current_target(root_windows[0]);
895   event_generator.PressKey(ui::VKEY_D, 0);
896   event_generator.ReleaseKey(ui::VKEY_D, 0);
897   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
898   EXPECT_EQ("abcd", base::UTF16ToASCII(textfield->text()));
899 
900   event_generator.set_current_target(root_windows[1]);
901   event_generator.PressKey(ui::VKEY_E, 0);
902   event_generator.ReleaseKey(ui::VKEY_E, 0);
903   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
904   EXPECT_EQ("abcde", base::UTF16ToASCII(textfield->text()));
905 }
906 
TEST_F(ExtendedDesktopTest,PassiveGrab)907 TEST_F(ExtendedDesktopTest, PassiveGrab) {
908   if (!SupportsMultipleDisplays())
909     return;
910 
911   EventLocationRecordingEventHandler event_handler;
912   ash::Shell::GetInstance()->AddPreTargetHandler(&event_handler);
913 
914   UpdateDisplay("300x300,200x200");
915 
916   views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
917   widget->Show();
918   ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
919 
920   ui::test::EventGenerator& generator(GetEventGenerator());
921   generator.MoveMouseTo(150, 150);
922   EXPECT_EQ("100,100 150,150", event_handler.GetLocationsAndReset());
923 
924   generator.PressLeftButton();
925   generator.MoveMouseTo(400, 150);
926 
927   EXPECT_EQ("350,100 400,150", event_handler.GetLocationsAndReset());
928 
929   generator.ReleaseLeftButton();
930   EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
931 
932   generator.MoveMouseTo(400, 150);
933   EXPECT_EQ("100,150 100,150", event_handler.GetLocationsAndReset());
934 
935   ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
936 }
937 
938 }  // namespace ash
939