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 "ui/views/widget/native_widget_aura.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/command_line.h"
11 #include "base/macros.h"
12 #include "base/run_loop.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/aura/client/aura_constants.h"
15 #include "ui/aura/env.h"
16 #include "ui/aura/layout_manager.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_observer.h"
19 #include "ui/aura/window_tree_host.h"
20 #include "ui/events/event.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/views/layout/fill_layout.h"
23 #include "ui/views/test/views_test_base.h"
24 #include "ui/views/test/widget_test.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/widget/widget_delegate.h"
27 #include "ui/wm/core/base_focus_rules.h"
28 #include "ui/wm/core/default_activation_client.h"
29 #include "ui/wm/core/focus_controller.h"
30 #include "ui/wm/core/transient_window_manager.h"
31 
32 namespace views {
33 namespace {
34 
Init(aura::Window * parent,Widget * widget)35 NativeWidgetAura* Init(aura::Window* parent, Widget* widget) {
36   Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
37   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
38   params.parent = parent;
39   widget->Init(std::move(params));
40   return static_cast<NativeWidgetAura*>(widget->native_widget());
41 }
42 
43 // TestFocusRules is intended to provide a way to manually set a window's
44 // activatability so that the focus rules can be tested.
45 class TestFocusRules : public wm::BaseFocusRules {
46  public:
47   TestFocusRules() = default;
48   ~TestFocusRules() override = default;
49 
set_can_activate(bool can_activate)50   void set_can_activate(bool can_activate) { can_activate_ = can_activate; }
51 
52   // wm::BaseFocusRules overrides:
SupportsChildActivation(const aura::Window * window) const53   bool SupportsChildActivation(const aura::Window* window) const override {
54     return true;
55   }
56 
CanActivateWindow(const aura::Window * window) const57   bool CanActivateWindow(const aura::Window* window) const override {
58     return can_activate_;
59   }
60 
61  private:
62   bool can_activate_ = true;
63 
64   DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
65 };
66 
67 class NativeWidgetAuraTest : public ViewsTestBase {
68  public:
69   NativeWidgetAuraTest() = default;
70   ~NativeWidgetAuraTest() override = default;
71 
test_focus_rules()72   TestFocusRules* test_focus_rules() { return test_focus_rules_; }
73 
74   // testing::Test overrides:
SetUp()75   void SetUp() override {
76     ViewsTestBase::SetUp();
77     test_focus_rules_ = new TestFocusRules;
78     focus_controller_ =
79         std::make_unique<wm::FocusController>(test_focus_rules_);
80     wm::SetActivationClient(root_window(), focus_controller_.get());
81     host()->SetBoundsInPixels(gfx::Rect(640, 480));
82   }
83 
84  private:
85   std::unique_ptr<wm::FocusController> focus_controller_;
86   TestFocusRules* test_focus_rules_;
87 
88   DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest);
89 };
90 
TEST_F(NativeWidgetAuraTest,CenterWindowLargeParent)91 TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
92   // Make a parent window larger than the host represented by
93   // WindowEventDispatcher.
94   std::unique_ptr<aura::Window> parent(new aura::Window(nullptr));
95   parent->Init(ui::LAYER_NOT_DRAWN);
96   parent->SetBounds(gfx::Rect(0, 0, 1024, 800));
97   std::unique_ptr<Widget> widget(new Widget());
98   NativeWidgetAura* window = Init(parent.get(), widget.get());
99 
100   window->CenterWindow(gfx::Size(100, 100));
101   EXPECT_EQ(gfx::Rect((640 - 100) / 2, (480 - 100) / 2, 100, 100),
102             window->GetNativeWindow()->bounds());
103   widget->CloseNow();
104 }
105 
TEST_F(NativeWidgetAuraTest,CenterWindowSmallParent)106 TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) {
107   // Make a parent window smaller than the host represented by
108   // WindowEventDispatcher.
109   std::unique_ptr<aura::Window> parent(new aura::Window(nullptr));
110   parent->Init(ui::LAYER_NOT_DRAWN);
111   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
112   std::unique_ptr<Widget> widget(new Widget());
113   NativeWidgetAura* window = Init(parent.get(), widget.get());
114 
115   window->CenterWindow(gfx::Size(100, 100));
116   EXPECT_EQ(gfx::Rect((480 - 100) / 2, (320 - 100) / 2, 100, 100),
117             window->GetNativeWindow()->bounds());
118   widget->CloseNow();
119 }
120 
121 // Verifies CenterWindow() constrains to parent size.
TEST_F(NativeWidgetAuraTest,CenterWindowSmallParentNotAtOrigin)122 TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
123   // Make a parent window smaller than the host represented by
124   // WindowEventDispatcher and offset it slightly from the origin.
125   std::unique_ptr<aura::Window> parent(new aura::Window(nullptr));
126   parent->Init(ui::LAYER_NOT_DRAWN);
127   parent->SetBounds(gfx::Rect(20, 40, 480, 320));
128   std::unique_ptr<Widget> widget(new Widget());
129   NativeWidgetAura* window = Init(parent.get(), widget.get());
130   window->CenterWindow(gfx::Size(500, 600));
131 
132   // |window| should be no bigger than |parent|.
133   EXPECT_EQ("20,40 480x320", window->GetNativeWindow()->bounds().ToString());
134   widget->CloseNow();
135 }
136 
TEST_F(NativeWidgetAuraTest,CreateMinimized)137 TEST_F(NativeWidgetAuraTest, CreateMinimized) {
138   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
139   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
140   params.parent = nullptr;
141   params.context = root_window();
142   params.show_state = ui::SHOW_STATE_MINIMIZED;
143   params.bounds.SetRect(0, 0, 1024, 800);
144   std::unique_ptr<Widget> widget(new Widget());
145   widget->Init(std::move(params));
146   widget->Show();
147 
148   EXPECT_TRUE(widget->IsMinimized());
149   widget->CloseNow();
150 }
151 
152 // Tests that GetRestoreBounds returns the window bounds even if the window is
153 // transformed.
TEST_F(NativeWidgetAuraTest,RestoreBounds)154 TEST_F(NativeWidgetAuraTest, RestoreBounds) {
155   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
156   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
157   params.parent = nullptr;
158   params.context = root_window();
159   params.bounds.SetRect(0, 0, 400, 400);
160   auto widget = std::make_unique<Widget>();
161   widget->Init(std::move(params));
162   widget->Show();
163   EXPECT_EQ(gfx::Rect(400, 400), widget->GetRestoredBounds());
164 
165   gfx::Transform transform;
166   transform.Translate(100.f, 100.f);
167   widget->GetNativeWindow()->SetTransform(transform);
168   EXPECT_EQ(gfx::Rect(400, 400), widget->GetRestoredBounds());
169 }
170 
171 // A WindowObserver that counts kShowStateKey property changes.
172 class TestWindowObserver : public aura::WindowObserver {
173  public:
TestWindowObserver(gfx::NativeWindow window)174   explicit TestWindowObserver(gfx::NativeWindow window) : window_(window) {
175     window_->AddObserver(this);
176   }
~TestWindowObserver()177   ~TestWindowObserver() override { window_->RemoveObserver(this); }
178 
179   // aura::WindowObserver:
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)180   void OnWindowPropertyChanged(aura::Window* window,
181                                const void* key,
182                                intptr_t old) override {
183     if (key != aura::client::kShowStateKey)
184       return;
185     count_++;
186     state_ = window_->GetProperty(aura::client::kShowStateKey);
187   }
188 
count() const189   int count() const { return count_; }
state() const190   ui::WindowShowState state() const { return state_; }
Reset()191   void Reset() { count_ = 0; }
192 
193  private:
194   gfx::NativeWindow window_;
195   int count_ = 0;
196   ui::WindowShowState state_ = ui::WindowShowState::SHOW_STATE_DEFAULT;
197 
198   DISALLOW_COPY_AND_ASSIGN(TestWindowObserver);
199 };
200 
201 // Tests that window transitions from normal to minimized and back do not
202 // involve extra show state transitions.
TEST_F(NativeWidgetAuraTest,ToggleState)203 TEST_F(NativeWidgetAuraTest, ToggleState) {
204   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
205   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
206   params.parent = nullptr;
207   params.context = root_window();
208   params.show_state = ui::SHOW_STATE_NORMAL;
209   params.bounds.SetRect(0, 0, 1024, 800);
210   Widget widget;
211   widget.Init(std::move(params));
212   std::unique_ptr<TestWindowObserver> observer(
213       new TestWindowObserver(widget.GetNativeWindow()));
214   widget.Show();
215   EXPECT_FALSE(widget.IsMinimized());
216   EXPECT_EQ(0, observer->count());
217   EXPECT_EQ(ui::WindowShowState::SHOW_STATE_DEFAULT, observer->state());
218 
219   widget.Minimize();
220   EXPECT_TRUE(widget.IsMinimized());
221   EXPECT_EQ(1, observer->count());
222   EXPECT_EQ(ui::WindowShowState::SHOW_STATE_MINIMIZED, observer->state());
223   observer->Reset();
224 
225   widget.Show();
226   widget.Restore();
227   EXPECT_EQ(1, observer->count());
228   EXPECT_EQ(ui::WindowShowState::SHOW_STATE_NORMAL, observer->state());
229 
230   observer.reset();
231   EXPECT_FALSE(widget.IsMinimized());
232   widget.CloseNow();
233 }
234 
235 class TestLayoutManagerBase : public aura::LayoutManager {
236  public:
237   TestLayoutManagerBase() = default;
238   ~TestLayoutManagerBase() override = default;
239 
240   // aura::LayoutManager:
OnWindowResized()241   void OnWindowResized() override {}
OnWindowAddedToLayout(aura::Window * child)242   void OnWindowAddedToLayout(aura::Window* child) override {}
OnWillRemoveWindowFromLayout(aura::Window * child)243   void OnWillRemoveWindowFromLayout(aura::Window* child) override {}
OnWindowRemovedFromLayout(aura::Window * child)244   void OnWindowRemovedFromLayout(aura::Window* child) override {}
OnChildWindowVisibilityChanged(aura::Window * child,bool visible)245   void OnChildWindowVisibilityChanged(aura::Window* child,
246                                       bool visible) override {}
SetChildBounds(aura::Window * child,const gfx::Rect & requested_bounds)247   void SetChildBounds(aura::Window* child,
248                       const gfx::Rect& requested_bounds) override {}
249 
250  private:
251   DISALLOW_COPY_AND_ASSIGN(TestLayoutManagerBase);
252 };
253 
254 // Used by ShowMaximizedDoesntBounceAround. See it for details.
255 class MaximizeLayoutManager : public TestLayoutManagerBase {
256  public:
257   MaximizeLayoutManager() = default;
258   ~MaximizeLayoutManager() override = default;
259 
260  private:
261   // aura::LayoutManager:
OnWindowAddedToLayout(aura::Window * child)262   void OnWindowAddedToLayout(aura::Window* child) override {
263     // This simulates what happens when adding a maximized window.
264     SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300));
265   }
266 
267   DISALLOW_COPY_AND_ASSIGN(MaximizeLayoutManager);
268 };
269 
270 // This simulates BrowserView, which creates a custom RootView so that
271 // OnNativeWidgetSizeChanged that is invoked during Init matters.
272 class TestWidget : public Widget {
273  public:
274   TestWidget() = default;
275 
276   // Returns true if the size changes to a non-empty size, and then to another
277   // size.
did_size_change_more_than_once() const278   bool did_size_change_more_than_once() const {
279     return did_size_change_more_than_once_;
280   }
281 
OnNativeWidgetSizeChanged(const gfx::Size & new_size)282   void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override {
283     if (last_size_.IsEmpty())
284       last_size_ = new_size;
285     else if (!did_size_change_more_than_once_ && new_size != last_size_)
286       did_size_change_more_than_once_ = true;
287     Widget::OnNativeWidgetSizeChanged(new_size);
288   }
289 
290  private:
291   bool did_size_change_more_than_once_ = false;
292   gfx::Size last_size_;
293 
294   DISALLOW_COPY_AND_ASSIGN(TestWidget);
295 };
296 
297 // Verifies the size of the widget doesn't change more than once during Init if
298 // the window ends up maximized. This is important as otherwise
299 // RenderWidgetHostViewAura ends up getting resized during construction, which
300 // leads to noticable flashes.
TEST_F(NativeWidgetAuraTest,ShowMaximizedDoesntBounceAround)301 TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
302   root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
303   root_window()->SetLayoutManager(new MaximizeLayoutManager);
304   std::unique_ptr<TestWidget> widget(new TestWidget());
305   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
306   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
307   params.parent = nullptr;
308   params.context = root_window();
309   params.show_state = ui::SHOW_STATE_MAXIMIZED;
310   params.bounds = gfx::Rect(10, 10, 100, 200);
311   widget->Init(std::move(params));
312   EXPECT_FALSE(widget->did_size_change_more_than_once());
313   widget->CloseNow();
314 }
315 
316 class PropertyTestLayoutManager : public TestLayoutManagerBase {
317  public:
318   PropertyTestLayoutManager() = default;
319   ~PropertyTestLayoutManager() override = default;
320 
added() const321   bool added() const { return added_; }
322 
323  private:
324   // aura::LayoutManager:
OnWindowAddedToLayout(aura::Window * child)325   void OnWindowAddedToLayout(aura::Window* child) override {
326     EXPECT_EQ(aura::client::kResizeBehaviorCanResize |
327                   aura::client::kResizeBehaviorCanMaximize |
328                   aura::client::kResizeBehaviorCanMinimize,
329               child->GetProperty(aura::client::kResizeBehaviorKey));
330     added_ = true;
331   }
332 
333   bool added_ = false;
334 
335   DISALLOW_COPY_AND_ASSIGN(PropertyTestLayoutManager);
336 };
337 
338 // Verifies the resize behavior when added to the layout manager.
TEST_F(NativeWidgetAuraTest,TestPropertiesWhenAddedToLayout)339 TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) {
340   root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
341   PropertyTestLayoutManager* layout_manager = new PropertyTestLayoutManager();
342   root_window()->SetLayoutManager(layout_manager);
343   std::unique_ptr<TestWidget> widget(new TestWidget());
344   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
345   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
346   params.delegate = new WidgetDelegate();
347   params.delegate->SetOwnedByWidget(true);
348   params.delegate->SetHasWindowSizeControls(true);
349   params.parent = nullptr;
350   params.context = root_window();
351   widget->Init(std::move(params));
352   EXPECT_TRUE(layout_manager->added());
353   widget->CloseNow();
354 }
355 
TEST_F(NativeWidgetAuraTest,GetClientAreaScreenBounds)356 TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
357   // Create a widget.
358   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
359   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
360   params.context = root_window();
361   params.bounds.SetRect(10, 20, 300, 400);
362   std::unique_ptr<Widget> widget(new Widget());
363   widget->Init(std::move(params));
364 
365   // For Aura, client area bounds match window bounds.
366   gfx::Rect client_bounds = widget->GetClientAreaBoundsInScreen();
367   EXPECT_EQ(10, client_bounds.x());
368   EXPECT_EQ(20, client_bounds.y());
369   EXPECT_EQ(300, client_bounds.width());
370   EXPECT_EQ(400, client_bounds.height());
371 }
372 
373 // View subclass that tracks whether it has gotten a gesture event.
374 class GestureTrackingView : public View {
375  public:
376   GestureTrackingView() = default;
377 
set_consume_gesture_event(bool value)378   void set_consume_gesture_event(bool value) { consume_gesture_event_ = value; }
379 
clear_got_gesture_event()380   void clear_got_gesture_event() { got_gesture_event_ = false; }
got_gesture_event() const381   bool got_gesture_event() const { return got_gesture_event_; }
382 
383   // View overrides:
OnGestureEvent(ui::GestureEvent * event)384   void OnGestureEvent(ui::GestureEvent* event) override {
385     got_gesture_event_ = true;
386     if (consume_gesture_event_)
387       event->StopPropagation();
388   }
389 
390  private:
391   // Was OnGestureEvent() invoked?
392   bool got_gesture_event_ = false;
393 
394   // Dictates what OnGestureEvent() returns.
395   bool consume_gesture_event_ = true;
396 
397   DISALLOW_COPY_AND_ASSIGN(GestureTrackingView);
398 };
399 
400 // Verifies a capture isn't set on touch press and that the view that gets
401 // the press gets the release.
TEST_F(NativeWidgetAuraTest,DontCaptureOnGesture)402 TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
403   // Create two views (both sized the same). |child| is configured not to
404   // consume the gesture event.
405   auto content_view = std::make_unique<GestureTrackingView>();
406   GestureTrackingView* child = new GestureTrackingView();
407   child->set_consume_gesture_event(false);
408   content_view->SetLayoutManager(std::make_unique<FillLayout>());
409   content_view->AddChildView(child);
410   std::unique_ptr<TestWidget> widget(new TestWidget());
411   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
412   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
413   params.context = root_window();
414   params.bounds = gfx::Rect(0, 0, 100, 200);
415   widget->Init(std::move(params));
416   GestureTrackingView* view = widget->SetContentsView(std::move(content_view));
417   widget->Show();
418 
419   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51),
420                        ui::EventTimeForNow(),
421                        ui::PointerDetails(ui::EventPointerType::kTouch, 1));
422   ui::EventDispatchDetails details = event_sink()->OnEventFromSource(&press);
423   ASSERT_FALSE(details.dispatcher_destroyed);
424   // Both views should get the press.
425   EXPECT_TRUE(view->got_gesture_event());
426   EXPECT_TRUE(child->got_gesture_event());
427   view->clear_got_gesture_event();
428   child->clear_got_gesture_event();
429   // Touch events should not automatically grab capture.
430   EXPECT_FALSE(widget->HasCapture());
431 
432   // Release touch. Only |view| should get the release since that it consumed
433   // the press.
434   ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251),
435                          ui::EventTimeForNow(),
436                          ui::PointerDetails(ui::EventPointerType::kTouch, 1));
437   details = event_sink()->OnEventFromSource(&release);
438   ASSERT_FALSE(details.dispatcher_destroyed);
439   EXPECT_TRUE(view->got_gesture_event());
440   EXPECT_FALSE(child->got_gesture_event());
441   view->clear_got_gesture_event();
442 }
443 
444 // Verifies views with layers are targeted for events properly.
TEST_F(NativeWidgetAuraTest,PreferViewLayersToChildWindows)445 TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
446   // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
447   std::unique_ptr<Widget> parent(new Widget());
448   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
449   parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
450   parent_params.context = root_window();
451   parent->Init(std::move(parent_params));
452   View* parent_root = parent->SetContentsView(std::make_unique<View>());
453   parent->SetBounds(gfx::Rect(0, 0, 400, 400));
454   parent->Show();
455 
456   std::unique_ptr<Widget> child(new Widget());
457   Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
458   child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
459   child_params.parent = parent->GetNativeWindow();
460   child->Init(std::move(child_params));
461   child->SetBounds(gfx::Rect(0, 0, 200, 200));
462   child->Show();
463 
464   // Point is over |child|.
465   EXPECT_EQ(
466       child->GetNativeWindow(),
467       parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50)));
468 
469   // Create a view with a layer and stack it at the bottom (below |child|).
470   View* view_with_layer = new View;
471   parent_root->AddChildView(view_with_layer);
472   view_with_layer->SetBounds(0, 0, 50, 50);
473   view_with_layer->SetPaintToLayer();
474 
475   // Make sure that |child| still gets the event.
476   EXPECT_EQ(
477       child->GetNativeWindow(),
478       parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20)));
479 
480   // Move |view_with_layer| to the top and make sure it gets the
481   // event when the point is within |view_with_layer|'s bounds.
482   view_with_layer->layer()->parent()->StackAtTop(view_with_layer->layer());
483   EXPECT_EQ(
484       parent->GetNativeWindow(),
485       parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20)));
486 
487   // Point is over |child|, it should get the event.
488   EXPECT_EQ(
489       child->GetNativeWindow(),
490       parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(70, 70)));
491 
492   delete view_with_layer;
493   view_with_layer = nullptr;
494 
495   EXPECT_EQ(
496       child->GetNativeWindow(),
497       parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20)));
498 }
499 
500 // Verifies views with layers are targeted for events properly.
TEST_F(NativeWidgetAuraTest,ShouldDescendIntoChildForEventHandlingChecksVisibleBounds)501 TEST_F(NativeWidgetAuraTest,
502        ShouldDescendIntoChildForEventHandlingChecksVisibleBounds) {
503   // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
504   Widget parent;
505   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
506   parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
507   parent_params.context = root_window();
508   parent.Init(std::move(parent_params));
509   View* parent_root_view = parent.SetContentsView(std::make_unique<View>());
510   parent.SetBounds(gfx::Rect(0, 0, 400, 400));
511   parent.Show();
512 
513   Widget child;
514   Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
515   child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
516   child_params.parent = parent.GetNativeWindow();
517   child.Init(std::move(child_params));
518   child.SetBounds(gfx::Rect(0, 0, 200, 200));
519   child.Show();
520 
521   // Point is over |child|.
522   EXPECT_EQ(
523       child.GetNativeWindow(),
524       parent.GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50)));
525 
526   View* parent_root_view_child = new View;
527   parent_root_view->AddChildView(parent_root_view_child);
528   parent_root_view_child->SetBounds(0, 0, 10, 10);
529 
530   // Create a View whose layer extends outside the bounds of its parent. Event
531   // targetting should only consider the visible bounds.
532   View* parent_root_view_child_child = new View;
533   parent_root_view_child->AddChildView(parent_root_view_child_child);
534   parent_root_view_child_child->SetBounds(0, 0, 100, 100);
535   parent_root_view_child_child->SetPaintToLayer();
536   parent_root_view_child_child->layer()->parent()->StackAtTop(
537       parent_root_view_child_child->layer());
538 
539   // 20,20 is over |parent_root_view_child_child|'s layer, but not the visible
540   // bounds of |parent_root_view_child_child|, so |child| should be the event
541   // target.
542   EXPECT_EQ(
543       child.GetNativeWindow(),
544       parent.GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20)));
545 }
546 
547 // Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey,
548 // and activating the window clears it.
TEST_F(NativeWidgetAuraTest,FlashFrame)549 TEST_F(NativeWidgetAuraTest, FlashFrame) {
550   std::unique_ptr<Widget> widget(new Widget());
551   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
552   params.context = root_window();
553   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
554   widget->Init(std::move(params));
555   aura::Window* window = widget->GetNativeWindow();
556   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
557   widget->FlashFrame(true);
558   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
559   widget->FlashFrame(false);
560   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
561   widget->FlashFrame(true);
562   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
563   widget->Activate();
564   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
565 }
566 
TEST_F(NativeWidgetAuraTest,NoCrashOnThemeAfterClose)567 TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) {
568   std::unique_ptr<aura::Window> parent(new aura::Window(nullptr));
569   parent->Init(ui::LAYER_NOT_DRAWN);
570   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
571   std::unique_ptr<Widget> widget(new Widget());
572   Init(parent.get(), widget.get());
573   widget->Show();
574   widget->Close();
575   base::RunLoop().RunUntilIdle();
576   widget->GetNativeTheme();  // Shouldn't crash.
577 }
578 
579 // Used to track calls to WidgetDelegate::OnWidgetMove().
580 class MoveTestWidgetDelegate : public WidgetDelegateView {
581  public:
582   MoveTestWidgetDelegate() = default;
583   ~MoveTestWidgetDelegate() override = default;
584 
ClearGotMove()585   void ClearGotMove() { got_move_ = false; }
got_move() const586   bool got_move() const { return got_move_; }
587 
588   // WidgetDelegate overrides:
OnWidgetMove()589   void OnWidgetMove() override { got_move_ = true; }
590 
591  private:
592   bool got_move_ = false;
593 
594   DISALLOW_COPY_AND_ASSIGN(MoveTestWidgetDelegate);
595 };
596 
597 // This test simulates what happens when a window is normally maximized. That
598 // is, it's layer is acquired for animation then the window is maximized.
599 // Acquiring the layer resets the bounds of the window. This test verifies the
600 // Widget is still notified correctly of a move in this case.
TEST_F(NativeWidgetAuraTest,OnWidgetMovedInvokedAfterAcquireLayer)601 TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) {
602   // |delegate| deletes itself when the widget is destroyed.
603   MoveTestWidgetDelegate* delegate = new MoveTestWidgetDelegate;
604   Widget* widget = Widget::CreateWindowWithContext(delegate, root_window(),
605                                                    gfx::Rect(10, 10, 100, 200));
606   widget->Show();
607   delegate->ClearGotMove();
608   // Simulate a maximize with animation.
609   widget->GetNativeView()->RecreateLayer();
610   widget->SetBounds(gfx::Rect(0, 0, 500, 500));
611   EXPECT_TRUE(delegate->got_move());
612   widget->CloseNow();
613 }
614 
615 // Tests that if a widget has a view which should be initially focused when the
616 // widget is shown, this view should not get focused if the associated window
617 // can not be activated.
TEST_F(NativeWidgetAuraTest,PreventFocusOnNonActivableWindow)618 TEST_F(NativeWidgetAuraTest, PreventFocusOnNonActivableWindow) {
619   test_focus_rules()->set_can_activate(false);
620   test::TestInitialFocusWidgetDelegate delegate(root_window());
621   delegate.GetWidget()->Show();
622   EXPECT_FALSE(delegate.view()->HasFocus());
623 
624   test_focus_rules()->set_can_activate(true);
625   test::TestInitialFocusWidgetDelegate delegate2(root_window());
626   delegate2.GetWidget()->Show();
627   EXPECT_TRUE(delegate2.view()->HasFocus());
628 }
629 
630 // Tests that the transient child bubble window is only visible if the parent is
631 // visible.
TEST_F(NativeWidgetAuraTest,VisibilityOfChildBubbleWindow)632 TEST_F(NativeWidgetAuraTest, VisibilityOfChildBubbleWindow) {
633   // Create a parent window.
634   Widget parent;
635   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW);
636   parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
637   parent_params.context = root_window();
638   parent.Init(std::move(parent_params));
639   parent.SetBounds(gfx::Rect(0, 0, 480, 320));
640 
641   // Add a child bubble window to the above parent window and show it.
642   Widget child;
643   Widget::InitParams child_params(Widget::InitParams::TYPE_BUBBLE);
644   child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
645   child_params.parent = parent.GetNativeWindow();
646   child.Init(std::move(child_params));
647   child.SetBounds(gfx::Rect(0, 0, 200, 200));
648   child.Show();
649 
650   // Check that the bubble window is added as the transient child and it is
651   // hidden because parent window is hidden.
652   wm::TransientWindowManager* manager =
653       wm::TransientWindowManager::GetOrCreate(child.GetNativeWindow());
654   EXPECT_EQ(parent.GetNativeWindow(), manager->transient_parent());
655   EXPECT_FALSE(parent.IsVisible());
656   EXPECT_FALSE(child.IsVisible());
657 
658   // Show the parent window should make the transient child bubble visible.
659   parent.Show();
660   EXPECT_TRUE(parent.IsVisible());
661   EXPECT_TRUE(child.IsVisible());
662 }
663 
664 // Tests that for a child transient window, if its modal type is
665 // ui::MODAL_TYPE_WINDOW, then its visibility is controlled by its transient
666 // parent's visibility.
TEST_F(NativeWidgetAuraTest,TransientChildModalWindowVisibility)667 TEST_F(NativeWidgetAuraTest, TransientChildModalWindowVisibility) {
668   // Create a parent window.
669   Widget parent;
670   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW);
671   parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
672   parent_params.context = root_window();
673   parent.Init(std::move(parent_params));
674   parent.SetBounds(gfx::Rect(0, 0, 400, 400));
675   parent.Show();
676   EXPECT_TRUE(parent.IsVisible());
677 
678   // Create a ui::MODAL_TYPE_WINDOW modal type transient child window.
679   Widget child;
680   Widget::InitParams child_params(Widget::InitParams::TYPE_WINDOW);
681   child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
682   child_params.parent = parent.GetNativeWindow();
683   child_params.delegate = new WidgetDelegate;
684   child_params.delegate->SetOwnedByWidget(true);
685   child_params.delegate->SetModalType(ui::MODAL_TYPE_WINDOW);
686   child.Init(std::move(child_params));
687   child.SetBounds(gfx::Rect(0, 0, 200, 200));
688   child.Show();
689   EXPECT_TRUE(parent.IsVisible());
690   EXPECT_TRUE(child.IsVisible());
691 
692   // Hide the parent window should also hide the child window.
693   parent.Hide();
694   EXPECT_FALSE(parent.IsVisible());
695   EXPECT_FALSE(child.IsVisible());
696 
697   // The child window can't be shown if the parent window is hidden.
698   child.Show();
699   EXPECT_FALSE(parent.IsVisible());
700   EXPECT_FALSE(child.IsVisible());
701 
702   parent.Show();
703   EXPECT_TRUE(parent.IsVisible());
704   EXPECT_TRUE(child.IsVisible());
705 }
706 
707 }  // namespace
708 }  // namespace views
709