MacViews: Use Mac's "Constrained Window Button" style for Button::STYLE_BUTTON LabelB...
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobba0c03b23426f86e8c5482f8e6e94be993c0691c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <set>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/events/test/event_generator.h"
21 #include "ui/gfx/geometry/point.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/views/bubble/bubble_delegate.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/test/test_views.h"
26 #include "ui/views/test/test_widget_observer.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/widget/native_widget_delegate.h"
29 #include "ui/views/widget/root_view.h"
30 #include "ui/views/widget/widget_deletion_observer.h"
31 #include "ui/views/window/dialog_delegate.h"
32 #include "ui/views/window/native_frame_view.h"
34 #if defined(OS_WIN)
35 #include "ui/aura/window.h"
36 #include "ui/aura/window_tree_host.h"
37 #include "ui/base/view_prop.h"
38 #include "ui/base/win/window_event_target.h"
39 #include "ui/views/win/hwnd_util.h"
40 #endif
42 #if defined(OS_MACOSX)
43 #include "base/mac/mac_util.h"
44 #endif
46 namespace views {
47 namespace test {
49 namespace {
51 // TODO(tdanderson): This utility function is used in different unittest
52 // files. Move to a common location to avoid
53 // repeated code.
54 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
55 gfx::Point tmp(p);
56 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
57 return tmp;
60 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
61 bool IsTestingSnowLeopard() {
62 #if defined(OS_MACOSX)
63 return base::mac::IsOSSnowLeopard();
64 #else
65 return false;
66 #endif
69 } // namespace
71 // A view that keeps track of the events it receives, optionally consuming them.
72 class EventCountView : public View {
73 public:
74 // Whether to call SetHandled() on events as they are received. For some event
75 // types, this will allow EventCountView to receives future events in the
76 // event sequence, such as a drag.
77 enum HandleMode {
78 PROPAGATE_EVENTS,
79 CONSUME_EVENTS
82 EventCountView()
83 : last_flags_(0),
84 handle_mode_(PROPAGATE_EVENTS) {}
86 ~EventCountView() override {}
88 int GetEventCount(ui::EventType type) {
89 return event_count_[type];
92 void ResetCounts() {
93 event_count_.clear();
96 int last_flags() const {
97 return last_flags_;
100 void set_handle_mode(HandleMode handle_mode) {
101 handle_mode_ = handle_mode;
104 protected:
105 // Overridden from View:
106 void OnMouseMoved(const ui::MouseEvent& event) override {
107 // MouseMove events are not re-dispatched from the RootView.
108 ++event_count_[ui::ET_MOUSE_MOVED];
109 last_flags_ = 0;
112 // Overridden from ui::EventHandler:
113 void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); }
114 void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); }
115 void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); }
116 void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); }
118 private:
119 void RecordEvent(ui::Event* event) {
120 ++event_count_[event->type()];
121 last_flags_ = event->flags();
122 if (handle_mode_ == CONSUME_EVENTS)
123 event->SetHandled();
126 std::map<ui::EventType, int> event_count_;
127 int last_flags_;
128 HandleMode handle_mode_;
130 DISALLOW_COPY_AND_ASSIGN(EventCountView);
133 // A view that keeps track of the events it receives, and consumes all scroll
134 // gesture events and ui::ET_SCROLL events.
135 class ScrollableEventCountView : public EventCountView {
136 public:
137 ScrollableEventCountView() {}
138 ~ScrollableEventCountView() override {}
140 private:
141 // Overridden from ui::EventHandler:
142 void OnGestureEvent(ui::GestureEvent* event) override {
143 EventCountView::OnGestureEvent(event);
144 switch (event->type()) {
145 case ui::ET_GESTURE_SCROLL_BEGIN:
146 case ui::ET_GESTURE_SCROLL_UPDATE:
147 case ui::ET_GESTURE_SCROLL_END:
148 case ui::ET_SCROLL_FLING_START:
149 event->SetHandled();
150 break;
151 default:
152 break;
156 void OnScrollEvent(ui::ScrollEvent* event) override {
157 EventCountView::OnScrollEvent(event);
158 if (event->type() == ui::ET_SCROLL)
159 event->SetHandled();
162 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
165 // A view that implements GetMinimumSize.
166 class MinimumSizeFrameView : public NativeFrameView {
167 public:
168 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
169 ~MinimumSizeFrameView() override {}
171 private:
172 // Overridden from View:
173 gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
175 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
178 // An event handler that simply keeps a count of the different types of events
179 // it receives.
180 class EventCountHandler : public ui::EventHandler {
181 public:
182 EventCountHandler() {}
183 ~EventCountHandler() override {}
185 int GetEventCount(ui::EventType type) {
186 return event_count_[type];
189 void ResetCounts() {
190 event_count_.clear();
193 protected:
194 // Overridden from ui::EventHandler:
195 void OnEvent(ui::Event* event) override {
196 RecordEvent(*event);
197 ui::EventHandler::OnEvent(event);
200 private:
201 void RecordEvent(const ui::Event& event) {
202 ++event_count_[event.type()];
205 std::map<ui::EventType, int> event_count_;
207 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
210 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate
211 // calls, and removes some of the boilerplate for initializing a Widget. Calls
212 // Widget::CloseNow() when destroyed if it hasn't already been done.
213 class TestDesktopWidgetDelegate : public WidgetDelegate {
214 public:
215 TestDesktopWidgetDelegate() : widget_(new Widget) {}
217 ~TestDesktopWidgetDelegate() override {
218 if (widget_)
219 widget_->CloseNow();
220 EXPECT_FALSE(widget_);
223 // Initialize the Widget, adding some meaningful default InitParams.
224 void InitWidget(Widget::InitParams init_params) {
225 init_params.delegate = this;
226 #if !defined(OS_CHROMEOS)
227 init_params.native_widget = new PlatformDesktopNativeWidget(widget_);
228 #endif
229 init_params.bounds = initial_bounds_;
230 widget_->Init(init_params);
233 // Set the contents view to be used during Widget initialization. For Widgets
234 // that use non-client views, this will be the contents_view used to
235 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise,
236 // it is the ContentsView of the Widget's RootView. Ownership passes to the
237 // view hierarchy during InitWidget().
238 void set_contents_view(View* contents_view) {
239 contents_view_ = contents_view;
242 int window_closing_count() const { return window_closing_count_; }
243 const gfx::Rect& initial_bounds() { return initial_bounds_; }
245 // WidgetDelegate overrides:
246 void WindowClosing() override {
247 window_closing_count_++;
248 widget_ = nullptr;
251 Widget* GetWidget() override { return widget_; }
252 const Widget* GetWidget() const override { return widget_; }
254 View* GetContentsView() override {
255 return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView();
258 bool ShouldAdvanceFocusToTopLevelWidget() const override {
259 return true; // Same default as DefaultWidgetDelegate in widget.cc.
262 private:
263 Widget* widget_;
264 View* contents_view_ = nullptr;
265 int window_closing_count_ = 0;
266 gfx::Rect initial_bounds_ = gfx::Rect(100, 100, 200, 200);
268 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate);
271 TEST_F(WidgetTest, WidgetInitParams) {
272 // Widgets are not transparent by default.
273 Widget::InitParams init1;
274 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
277 TEST_F(WidgetTest, NativeWindowProperty) {
278 const char* key = "foo";
279 int value = 3;
281 Widget* widget = CreateTopLevelPlatformWidget();
282 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
284 widget->SetNativeWindowProperty(key, &value);
285 EXPECT_EQ(&value, widget->GetNativeWindowProperty(key));
287 widget->SetNativeWindowProperty(key, nullptr);
288 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
290 widget->CloseNow();
293 ////////////////////////////////////////////////////////////////////////////////
294 // Widget::GetTopLevelWidget tests.
296 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
297 // Create a hierarchy of native widgets.
298 Widget* toplevel = CreateTopLevelPlatformWidget();
299 gfx::NativeView parent = toplevel->GetNativeView();
300 Widget* child = CreateChildPlatformWidget(parent);
302 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
303 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
305 toplevel->CloseNow();
306 // |child| should be automatically destroyed with |toplevel|.
309 // Test if a focus manager and an inputmethod work without CHECK failure
310 // when window activation changes.
311 TEST_F(WidgetTest, ChangeActivation) {
312 Widget* top1 = CreateTopLevelPlatformWidget();
313 top1->Show();
314 RunPendingMessages();
316 Widget* top2 = CreateTopLevelPlatformWidget();
317 top2->Show();
318 RunPendingMessages();
320 top1->Activate();
321 RunPendingMessages();
323 top2->Activate();
324 RunPendingMessages();
326 top1->Activate();
327 RunPendingMessages();
329 top1->CloseNow();
330 top2->CloseNow();
333 // Tests visibility of child widgets.
334 TEST_F(WidgetTest, Visibility) {
335 Widget* toplevel = CreateTopLevelPlatformWidget();
336 gfx::NativeView parent = toplevel->GetNativeView();
337 Widget* child = CreateChildPlatformWidget(parent);
339 EXPECT_FALSE(toplevel->IsVisible());
340 EXPECT_FALSE(child->IsVisible());
342 // Showing a child with a hidden parent keeps the child hidden.
343 child->Show();
344 EXPECT_FALSE(toplevel->IsVisible());
345 EXPECT_FALSE(child->IsVisible());
347 // Showing a hidden parent with a visible child shows both.
348 toplevel->Show();
349 EXPECT_TRUE(toplevel->IsVisible());
350 EXPECT_TRUE(child->IsVisible());
352 // Hiding a parent hides both parent and child.
353 toplevel->Hide();
354 EXPECT_FALSE(toplevel->IsVisible());
355 EXPECT_FALSE(child->IsVisible());
357 // Hiding a child while the parent is hidden keeps the child hidden when the
358 // parent is shown.
359 child->Hide();
360 toplevel->Show();
361 EXPECT_TRUE(toplevel->IsVisible());
362 EXPECT_FALSE(child->IsVisible());
364 toplevel->CloseNow();
365 // |child| should be automatically destroyed with |toplevel|.
368 // Test that child widgets are positioned relative to their parent.
369 TEST_F(WidgetTest, ChildBoundsRelativeToParent) {
370 Widget* toplevel = CreateTopLevelPlatformWidget();
371 Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
373 toplevel->SetBounds(gfx::Rect(160, 100, 320, 200));
374 child->SetBounds(gfx::Rect(0, 0, 320, 200));
376 child->Show();
377 toplevel->Show();
379 gfx::Rect toplevel_bounds = toplevel->GetWindowBoundsInScreen();
381 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
382 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds.OffsetFromOrigin());
384 // The child's origin is at (0, 0), but the same size, so bounds should match.
385 EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen());
387 toplevel->CloseNow();
390 // Test z-order of child widgets relative to their parent.
391 TEST_F(WidgetTest, ChildStackedRelativeToParent) {
392 Widget* parent = CreateTopLevelPlatformWidget();
393 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
395 parent->SetBounds(gfx::Rect(160, 100, 320, 200));
396 child->SetBounds(gfx::Rect(50, 50, 30, 20));
398 // Child shown first. Initially not visible, but on top of parent when shown.
399 // Use ShowInactive whenever showing the child, otherwise the usual activation
400 // logic will just put it on top anyway. Here, we want to ensure it is on top
401 // of its parent regardless.
402 child->ShowInactive();
403 EXPECT_FALSE(child->IsVisible());
405 parent->Show();
406 EXPECT_TRUE(child->IsVisible());
407 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
408 EXPECT_FALSE(IsWindowStackedAbove(parent, child)); // Sanity check.
410 Widget* popover = CreateTopLevelPlatformWidget();
411 popover->SetBounds(gfx::Rect(150, 90, 340, 240));
412 popover->Show();
414 EXPECT_TRUE(IsWindowStackedAbove(popover, child));
415 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
417 // Showing the parent again should raise it and its child above the popover.
418 parent->Show();
419 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
420 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
422 // Test grandchildren.
423 Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView());
424 grandchild->SetBounds(gfx::Rect(5, 5, 15, 10));
425 grandchild->ShowInactive();
426 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
427 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
428 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
430 popover->Show();
431 EXPECT_TRUE(IsWindowStackedAbove(popover, grandchild));
432 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
434 parent->Show();
435 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
436 EXPECT_TRUE(IsWindowStackedAbove(child, popover));
438 // Test hiding and reshowing.
439 parent->Hide();
440 EXPECT_FALSE(grandchild->IsVisible());
441 parent->Show();
443 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
444 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
445 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
447 grandchild->Hide();
448 EXPECT_FALSE(grandchild->IsVisible());
449 grandchild->ShowInactive();
451 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
452 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
453 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
455 popover->CloseNow();
456 parent->CloseNow();
459 ////////////////////////////////////////////////////////////////////////////////
460 // Widget ownership tests.
462 // Tests various permutations of Widget ownership specified in the
463 // InitParams::Ownership param.
465 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
466 class WidgetOwnershipTest : public WidgetTest {
467 public:
468 WidgetOwnershipTest() {}
469 ~WidgetOwnershipTest() override {}
471 void SetUp() override {
472 WidgetTest::SetUp();
473 desktop_widget_ = CreateTopLevelPlatformWidget();
476 void TearDown() override {
477 desktop_widget_->CloseNow();
478 WidgetTest::TearDown();
481 private:
482 Widget* desktop_widget_;
484 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
487 // A bag of state to monitor destructions.
488 struct OwnershipTestState {
489 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
491 bool widget_deleted;
492 bool native_widget_deleted;
495 // A platform NativeWidget subclass that updates a bag of state when it is
496 // destroyed.
497 class OwnershipTestNativeWidget : public PlatformNativeWidget {
498 public:
499 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
500 OwnershipTestState* state)
501 : PlatformNativeWidget(delegate),
502 state_(state) {
504 ~OwnershipTestNativeWidget() override {
505 state_->native_widget_deleted = true;
508 private:
509 OwnershipTestState* state_;
511 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
514 // A views NativeWidget subclass that updates a bag of state when it is
515 // destroyed.
516 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
517 public:
518 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
519 OwnershipTestState* state)
520 : NativeWidgetCapture(delegate),
521 state_(state) {
523 ~OwnershipTestNativeWidgetAura() override {
524 state_->native_widget_deleted = true;
527 private:
528 OwnershipTestState* state_;
530 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
533 // A Widget subclass that updates a bag of state when it is destroyed.
534 class OwnershipTestWidget : public Widget {
535 public:
536 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
537 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
539 private:
540 OwnershipTestState* state_;
542 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
545 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
546 // widget.
547 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
548 OwnershipTestState state;
550 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
551 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
552 params.native_widget =
553 new OwnershipTestNativeWidgetAura(widget.get(), &state);
554 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
555 widget->Init(params);
557 // Now delete the Widget, which should delete the NativeWidget.
558 widget.reset();
560 EXPECT_TRUE(state.widget_deleted);
561 EXPECT_TRUE(state.native_widget_deleted);
563 // TODO(beng): write test for this ownership scenario and the NativeWidget
564 // being deleted out from under the Widget.
567 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
568 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
569 OwnershipTestState state;
571 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
572 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
573 params.native_widget =
574 new OwnershipTestNativeWidgetAura(widget.get(), &state);
575 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
576 widget->Init(params);
578 // Now delete the Widget, which should delete the NativeWidget.
579 widget.reset();
581 EXPECT_TRUE(state.widget_deleted);
582 EXPECT_TRUE(state.native_widget_deleted);
584 // TODO(beng): write test for this ownership scenario and the NativeWidget
585 // being deleted out from under the Widget.
588 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
589 // destroy the parent view.
590 TEST_F(WidgetOwnershipTest,
591 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
592 OwnershipTestState state;
594 Widget* toplevel = CreateTopLevelPlatformWidget();
596 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
597 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
598 params.native_widget =
599 new OwnershipTestNativeWidgetAura(widget.get(), &state);
600 params.parent = toplevel->GetNativeView();
601 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
602 widget->Init(params);
604 // Now close the toplevel, which deletes the view hierarchy.
605 toplevel->CloseNow();
607 RunPendingMessages();
609 // This shouldn't delete the widget because it shouldn't be deleted
610 // from the native side.
611 EXPECT_FALSE(state.widget_deleted);
612 EXPECT_FALSE(state.native_widget_deleted);
614 // Now delete it explicitly.
615 widget.reset();
617 EXPECT_TRUE(state.widget_deleted);
618 EXPECT_TRUE(state.native_widget_deleted);
621 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
622 // widget.
623 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
624 OwnershipTestState state;
626 Widget* widget = new OwnershipTestWidget(&state);
627 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
628 params.native_widget =
629 new OwnershipTestNativeWidgetAura(widget, &state);
630 widget->Init(params);
632 // Now destroy the native widget.
633 widget->CloseNow();
635 EXPECT_TRUE(state.widget_deleted);
636 EXPECT_TRUE(state.native_widget_deleted);
639 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
640 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
641 OwnershipTestState state;
643 Widget* toplevel = CreateTopLevelPlatformWidget();
645 Widget* widget = new OwnershipTestWidget(&state);
646 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
647 params.native_widget =
648 new OwnershipTestNativeWidgetAura(widget, &state);
649 params.parent = toplevel->GetNativeView();
650 widget->Init(params);
652 // Now destroy the native widget. This is achieved by closing the toplevel.
653 toplevel->CloseNow();
655 // The NativeWidget won't be deleted until after a return to the message loop
656 // so we have to run pending messages before testing the destruction status.
657 RunPendingMessages();
659 EXPECT_TRUE(state.widget_deleted);
660 EXPECT_TRUE(state.native_widget_deleted);
663 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
664 // widget, destroyed out from under it by the OS.
665 TEST_F(WidgetOwnershipTest,
666 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
667 OwnershipTestState state;
669 Widget* widget = new OwnershipTestWidget(&state);
670 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
671 params.native_widget =
672 new OwnershipTestNativeWidgetAura(widget, &state);
673 widget->Init(params);
675 // Now simulate a destroy of the platform native widget from the OS:
676 SimulateNativeDestroy(widget);
678 EXPECT_TRUE(state.widget_deleted);
679 EXPECT_TRUE(state.native_widget_deleted);
682 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
683 // destroyed by the view hierarchy that contains it.
684 TEST_F(WidgetOwnershipTest,
685 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
686 OwnershipTestState state;
688 Widget* toplevel = CreateTopLevelPlatformWidget();
690 Widget* widget = new OwnershipTestWidget(&state);
691 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
692 params.native_widget =
693 new OwnershipTestNativeWidgetAura(widget, &state);
694 params.parent = toplevel->GetNativeView();
695 widget->Init(params);
697 // Destroy the widget (achieved by closing the toplevel).
698 toplevel->CloseNow();
700 // The NativeWidget won't be deleted until after a return to the message loop
701 // so we have to run pending messages before testing the destruction status.
702 RunPendingMessages();
704 EXPECT_TRUE(state.widget_deleted);
705 EXPECT_TRUE(state.native_widget_deleted);
708 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
709 // we close it directly.
710 TEST_F(WidgetOwnershipTest,
711 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
712 OwnershipTestState state;
714 Widget* toplevel = CreateTopLevelPlatformWidget();
716 Widget* widget = new OwnershipTestWidget(&state);
717 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
718 params.native_widget =
719 new OwnershipTestNativeWidgetAura(widget, &state);
720 params.parent = toplevel->GetNativeView();
721 widget->Init(params);
723 // Destroy the widget.
724 widget->Close();
725 toplevel->CloseNow();
727 // The NativeWidget won't be deleted until after a return to the message loop
728 // so we have to run pending messages before testing the destruction status.
729 RunPendingMessages();
731 EXPECT_TRUE(state.widget_deleted);
732 EXPECT_TRUE(state.native_widget_deleted);
735 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
736 TEST_F(WidgetOwnershipTest,
737 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
738 OwnershipTestState state;
740 WidgetDelegateView* delegate_view = new WidgetDelegateView;
742 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
743 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
744 params.native_widget =
745 new OwnershipTestNativeWidgetAura(widget.get(), &state);
746 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
747 params.delegate = delegate_view;
748 widget->Init(params);
749 widget->SetContentsView(delegate_view);
751 // Now delete the Widget. There should be no crash or use-after-free.
752 widget.reset();
754 EXPECT_TRUE(state.widget_deleted);
755 EXPECT_TRUE(state.native_widget_deleted);
758 ////////////////////////////////////////////////////////////////////////////////
759 // Test to verify using various Widget methods doesn't crash when the underlying
760 // NativeView is destroyed.
762 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
763 public:
764 WidgetWithDestroyedNativeViewTest() {}
765 ~WidgetWithDestroyedNativeViewTest() override {}
767 void InvokeWidgetMethods(Widget* widget) {
768 widget->GetNativeView();
769 widget->GetNativeWindow();
770 ui::Accelerator accelerator;
771 widget->GetAccelerator(0, &accelerator);
772 widget->GetTopLevelWidget();
773 widget->GetWindowBoundsInScreen();
774 widget->GetClientAreaBoundsInScreen();
775 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
776 widget->SetSize(gfx::Size(10, 11));
777 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
778 widget->SetVisibilityChangedAnimationsEnabled(false);
779 widget->StackAtTop();
780 widget->IsClosed();
781 widget->Close();
782 widget->Hide();
783 widget->Activate();
784 widget->Deactivate();
785 widget->IsActive();
786 widget->DisableInactiveRendering();
787 widget->SetAlwaysOnTop(true);
788 widget->IsAlwaysOnTop();
789 widget->Maximize();
790 widget->Minimize();
791 widget->Restore();
792 widget->IsMaximized();
793 widget->IsFullscreen();
794 widget->SetOpacity(0);
795 widget->SetUseDragFrame(true);
796 widget->FlashFrame(true);
797 widget->IsVisible();
798 widget->GetThemeProvider();
799 widget->GetNativeTheme();
800 widget->GetFocusManager();
801 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
802 widget->IsMouseEventsEnabled();
803 widget->SetNativeWindowProperty("xx", widget);
804 widget->GetNativeWindowProperty("xx");
805 widget->GetFocusTraversable();
806 widget->GetLayer();
807 widget->ReorderNativeViews();
808 widget->SetCapture(widget->GetRootView());
809 widget->ReleaseCapture();
810 widget->HasCapture();
811 widget->GetWorkAreaBoundsInScreen();
812 widget->IsTranslucentWindowOpacitySupported();
815 private:
816 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
819 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
821 Widget widget;
822 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
823 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
824 widget.Init(params);
825 widget.Show();
827 widget.native_widget_private()->CloseNow();
828 InvokeWidgetMethods(&widget);
830 #if !defined(OS_CHROMEOS)
832 Widget widget;
833 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
834 params.native_widget = new PlatformDesktopNativeWidget(&widget);
835 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
836 widget.Init(params);
837 widget.Show();
839 widget.native_widget_private()->CloseNow();
840 InvokeWidgetMethods(&widget);
842 #endif
845 ////////////////////////////////////////////////////////////////////////////////
846 // Widget observer tests.
849 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
850 public:
851 WidgetObserverTest()
852 : active_(nullptr),
853 widget_closed_(nullptr),
854 widget_activated_(nullptr),
855 widget_shown_(nullptr),
856 widget_hidden_(nullptr),
857 widget_bounds_changed_(nullptr),
858 widget_to_close_on_hide_(nullptr) {
861 ~WidgetObserverTest() override {}
863 // Set a widget to Close() the next time the Widget being observed is hidden.
864 void CloseOnNextHide(Widget* widget) {
865 widget_to_close_on_hide_ = widget;
868 // Overridden from WidgetObserver:
869 void OnWidgetDestroying(Widget* widget) override {
870 if (active_ == widget)
871 active_ = nullptr;
872 widget_closed_ = widget;
875 void OnWidgetActivationChanged(Widget* widget, bool active) override {
876 if (active) {
877 if (widget_activated_)
878 widget_activated_->Deactivate();
879 widget_activated_ = widget;
880 active_ = widget;
881 } else {
882 if (widget_activated_ == widget)
883 widget_activated_ = nullptr;
884 widget_deactivated_ = widget;
888 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
889 if (visible) {
890 widget_shown_ = widget;
891 return;
893 widget_hidden_ = widget;
894 if (widget_to_close_on_hide_) {
895 widget_to_close_on_hide_->Close();
896 widget_to_close_on_hide_ = nullptr;
900 void OnWidgetBoundsChanged(Widget* widget,
901 const gfx::Rect& new_bounds) override {
902 widget_bounds_changed_ = widget;
905 void reset() {
906 active_ = nullptr;
907 widget_closed_ = nullptr;
908 widget_activated_ = nullptr;
909 widget_deactivated_ = nullptr;
910 widget_shown_ = nullptr;
911 widget_hidden_ = nullptr;
912 widget_bounds_changed_ = nullptr;
915 Widget* NewWidget() {
916 Widget* widget = CreateTopLevelNativeWidget();
917 widget->AddObserver(this);
918 return widget;
921 const Widget* active() const { return active_; }
922 const Widget* widget_closed() const { return widget_closed_; }
923 const Widget* widget_activated() const { return widget_activated_; }
924 const Widget* widget_deactivated() const { return widget_deactivated_; }
925 const Widget* widget_shown() const { return widget_shown_; }
926 const Widget* widget_hidden() const { return widget_hidden_; }
927 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
929 private:
930 Widget* active_;
932 Widget* widget_closed_;
933 Widget* widget_activated_;
934 Widget* widget_deactivated_;
935 Widget* widget_shown_;
936 Widget* widget_hidden_;
937 Widget* widget_bounds_changed_;
939 Widget* widget_to_close_on_hide_;
942 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
943 Widget* toplevel = CreateTopLevelPlatformWidget();
945 Widget* toplevel1 = NewWidget();
946 Widget* toplevel2 = NewWidget();
948 toplevel1->Show();
949 toplevel2->Show();
951 reset();
953 toplevel1->Activate();
955 RunPendingMessages();
956 EXPECT_EQ(toplevel1, widget_activated());
958 toplevel2->Activate();
959 RunPendingMessages();
960 EXPECT_EQ(toplevel1, widget_deactivated());
961 EXPECT_EQ(toplevel2, widget_activated());
962 EXPECT_EQ(toplevel2, active());
964 toplevel->CloseNow();
967 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
968 Widget* toplevel = CreateTopLevelPlatformWidget();
970 Widget* child1 = NewWidget();
971 Widget* child2 = NewWidget();
973 toplevel->Show();
974 child1->Show();
975 child2->Show();
977 reset();
979 child1->Hide();
980 EXPECT_EQ(child1, widget_hidden());
982 child2->Hide();
983 EXPECT_EQ(child2, widget_hidden());
985 child1->Show();
986 EXPECT_EQ(child1, widget_shown());
988 child2->Show();
989 EXPECT_EQ(child2, widget_shown());
991 toplevel->CloseNow();
994 TEST_F(WidgetObserverTest, DestroyBubble) {
995 Widget* anchor = CreateTopLevelPlatformWidget();
996 anchor->Show();
998 BubbleDelegateView* bubble_delegate =
999 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
1000 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1001 bubble_widget->Show();
1002 bubble_widget->CloseNow();
1004 anchor->Hide();
1005 anchor->CloseNow();
1008 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
1009 Widget* child1 = NewWidget();
1010 Widget* child2 = NewWidget();
1012 child1->OnNativeWidgetMove();
1013 EXPECT_EQ(child1, widget_bounds_changed());
1015 child2->OnNativeWidgetMove();
1016 EXPECT_EQ(child2, widget_bounds_changed());
1018 child1->OnNativeWidgetSizeChanged(gfx::Size());
1019 EXPECT_EQ(child1, widget_bounds_changed());
1021 child2->OnNativeWidgetSizeChanged(gfx::Size());
1022 EXPECT_EQ(child2, widget_bounds_changed());
1024 child2->CloseNow();
1025 child1->CloseNow();
1028 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
1029 // by the NativeWidget implementation.
1030 TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
1031 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
1032 // consistency across platforms.
1033 Widget* widget = new Widget(); // Note: owned by NativeWidget.
1034 widget->AddObserver(this);
1036 EXPECT_FALSE(widget_bounds_changed());
1038 // Init causes a bounds change, even while not showing. Note some platforms
1039 // cause a bounds change even when the bounds are empty. Mac does not.
1040 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
1041 params.bounds = gfx::Rect(0, 0, 100, 100);
1042 widget->Init(params);
1043 EXPECT_TRUE(widget_bounds_changed());
1044 reset();
1046 // Resizing while hidden, triggers a change.
1047 widget->SetSize(gfx::Size(160, 100));
1048 EXPECT_FALSE(widget->IsVisible());
1049 EXPECT_TRUE(widget_bounds_changed());
1050 reset();
1052 // Setting the same size does nothing.
1053 widget->SetSize(gfx::Size(160, 100));
1054 EXPECT_FALSE(widget_bounds_changed());
1055 reset();
1057 // Showing does nothing to the bounds.
1058 widget->Show();
1059 EXPECT_TRUE(widget->IsVisible());
1060 EXPECT_FALSE(widget_bounds_changed());
1061 reset();
1063 // Resizing while shown.
1064 widget->SetSize(gfx::Size(170, 100));
1065 EXPECT_TRUE(widget_bounds_changed());
1066 reset();
1068 // Resize to the same thing while shown does nothing.
1069 widget->SetSize(gfx::Size(170, 100));
1070 EXPECT_FALSE(widget_bounds_changed());
1071 reset();
1073 // No bounds change when closing.
1074 widget->CloseNow();
1075 EXPECT_FALSE(widget_bounds_changed());
1078 // Test correct behavior when widgets close themselves in response to visibility
1079 // changes.
1080 TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
1081 Widget* parent = NewWidget();
1082 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
1084 TestWidgetObserver child_observer(child);
1086 EXPECT_FALSE(parent->IsVisible());
1087 EXPECT_FALSE(child->IsVisible());
1089 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
1090 // child separately.
1091 parent->Show();
1092 EXPECT_TRUE(parent->IsVisible());
1093 EXPECT_TRUE(child->IsVisible());
1095 // Simulate a child widget that closes itself when the parent is hidden.
1096 CloseOnNextHide(child);
1097 EXPECT_FALSE(child_observer.widget_closed());
1098 parent->Hide();
1099 RunPendingMessages();
1100 EXPECT_TRUE(child_observer.widget_closed());
1102 parent->CloseNow();
1105 // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
1106 TEST_F(WidgetTest, GetWindowPlacement) {
1107 Widget* widget;
1108 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1109 // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
1110 // asynchronous. Also (harder) showing a window doesn't activate it without
1111 // user interaction (or extra steps only done for interactive ui tests).
1112 // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
1113 // TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
1114 widget = CreateTopLevelPlatformWidget();
1115 #else
1116 widget = CreateNativeDesktopWidget();
1117 #endif
1119 gfx::Rect expected_bounds(100, 110, 200, 220);
1120 widget->SetBounds(expected_bounds);
1121 widget->Show();
1123 // Start with something invalid to ensure it changes.
1124 ui::WindowShowState show_state = ui::SHOW_STATE_END;
1125 gfx::Rect restored_bounds;
1127 internal::NativeWidgetPrivate* native_widget =
1128 widget->native_widget_private();
1130 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1131 EXPECT_EQ(expected_bounds, restored_bounds);
1132 #if defined(OS_LINUX)
1133 // Non-desktop/Ash widgets start off in "default" until a Restore().
1134 EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
1135 widget->Restore();
1136 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1137 #endif
1138 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1140 widget->Minimize();
1141 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1142 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, show_state);
1143 EXPECT_EQ(expected_bounds, restored_bounds);
1145 widget->Restore();
1146 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1147 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1148 EXPECT_EQ(expected_bounds, restored_bounds);
1150 expected_bounds = gfx::Rect(130, 140, 230, 250);
1151 widget->SetBounds(expected_bounds);
1152 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1153 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1154 EXPECT_EQ(expected_bounds, restored_bounds);
1156 widget->SetFullscreen(true);
1157 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1159 #if defined(OS_WIN)
1160 // Desktop Aura widgets on Windows currently don't update show_state when
1161 // going fullscreen, and report restored_bounds as the full screen size.
1162 // See http://crbug.com/475813.
1163 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1164 #else
1165 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, show_state);
1166 EXPECT_EQ(expected_bounds, restored_bounds);
1167 #endif
1169 widget->SetFullscreen(false);
1170 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1171 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1172 EXPECT_EQ(expected_bounds, restored_bounds);
1174 widget->CloseNow();
1177 // Test that widget size constraints are properly applied immediately after
1178 // Init(), and that SetBounds() calls are appropriately clamped.
1179 TEST_F(WidgetTest, MinimumSizeConstraints) {
1180 TestDesktopWidgetDelegate delegate;
1181 gfx::Size minimum_size(100, 100);
1182 const gfx::Size smaller_size(90, 90);
1184 delegate.set_contents_view(new StaticSizedView(minimum_size));
1185 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1186 Widget* widget = delegate.GetWidget();
1188 // On desktop Linux, the Widget must be shown to ensure the window is mapped.
1189 // On other platforms this line is optional.
1190 widget->Show();
1192 // Sanity checks.
1193 EXPECT_GT(delegate.initial_bounds().width(), minimum_size.width());
1194 EXPECT_GT(delegate.initial_bounds().height(), minimum_size.height());
1195 EXPECT_EQ(delegate.initial_bounds().size(),
1196 widget->GetWindowBoundsInScreen().size());
1197 // Note: StaticSizedView doesn't currently provide a maximum size.
1198 EXPECT_EQ(gfx::Size(), widget->GetMaximumSize());
1200 if (!widget->ShouldUseNativeFrame()) {
1201 // The test environment may have dwm disabled on Windows. In this case,
1202 // CustomFrameView is used instead of the NativeFrameView, which will
1203 // provide a minimum size that includes frame decorations.
1204 minimum_size = widget->non_client_view()->GetWindowBoundsForClientBounds(
1205 gfx::Rect(minimum_size)).size();
1208 EXPECT_EQ(minimum_size, widget->GetMinimumSize());
1209 EXPECT_EQ(minimum_size, GetNativeWidgetMinimumContentSize(widget));
1211 // Trying to resize smaller than the minimum size should restrict the content
1212 // size to the minimum size.
1213 widget->SetBounds(gfx::Rect(smaller_size));
1214 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1216 widget->SetSize(smaller_size);
1217 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1218 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it.
1219 EXPECT_EQ(smaller_size, widget->GetClientAreaBoundsInScreen().size());
1220 #else
1221 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1222 #endif
1225 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1226 // widget is visible and not maximized or fullscreen.
1227 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
1228 // Choose test coordinates away from edges and dimensions that are "small"
1229 // (but not too small) to ensure the OS doesn't try to adjust them.
1230 const gfx::Rect kTestBounds(150, 150, 400, 300);
1231 const gfx::Size kTestSize(200, 180);
1233 // First test a toplevel widget.
1234 Widget* widget = CreateTopLevelPlatformWidget();
1235 widget->Show();
1237 EXPECT_NE(kTestSize.ToString(),
1238 widget->GetWindowBoundsInScreen().size().ToString());
1239 widget->SetSize(kTestSize);
1240 EXPECT_EQ(kTestSize.ToString(),
1241 widget->GetWindowBoundsInScreen().size().ToString());
1243 EXPECT_NE(kTestBounds.ToString(),
1244 widget->GetWindowBoundsInScreen().ToString());
1245 widget->SetBounds(kTestBounds);
1246 EXPECT_EQ(kTestBounds.ToString(),
1247 widget->GetWindowBoundsInScreen().ToString());
1249 // Changing just the size should not change the origin.
1250 widget->SetSize(kTestSize);
1251 EXPECT_EQ(kTestBounds.origin().ToString(),
1252 widget->GetWindowBoundsInScreen().origin().ToString());
1254 widget->CloseNow();
1256 // Same tests with a frameless window.
1257 widget = CreateTopLevelFramelessPlatformWidget();
1258 widget->Show();
1260 EXPECT_NE(kTestSize.ToString(),
1261 widget->GetWindowBoundsInScreen().size().ToString());
1262 widget->SetSize(kTestSize);
1263 EXPECT_EQ(kTestSize.ToString(),
1264 widget->GetWindowBoundsInScreen().size().ToString());
1266 EXPECT_NE(kTestBounds.ToString(),
1267 widget->GetWindowBoundsInScreen().ToString());
1268 widget->SetBounds(kTestBounds);
1269 EXPECT_EQ(kTestBounds.ToString(),
1270 widget->GetWindowBoundsInScreen().ToString());
1272 // For a frameless widget, the client bounds should also match.
1273 EXPECT_EQ(kTestBounds.ToString(),
1274 widget->GetClientAreaBoundsInScreen().ToString());
1276 // Verify origin is stable for a frameless window as well.
1277 widget->SetSize(kTestSize);
1278 EXPECT_EQ(kTestBounds.origin().ToString(),
1279 widget->GetWindowBoundsInScreen().origin().ToString());
1281 widget->CloseNow();
1284 // Before being enabled on Mac, this was #ifdef(false).
1285 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
1286 #if defined(OS_MACOSX)
1287 // Aura needs shell to maximize/fullscreen window.
1288 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1289 TEST_F(WidgetTest, GetRestoredBounds) {
1290 Widget* toplevel = CreateTopLevelPlatformWidget();
1291 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1292 toplevel->GetRestoredBounds().ToString());
1293 toplevel->Show();
1294 toplevel->Maximize();
1295 RunPendingMessages();
1296 #if defined(OS_MACOSX)
1297 // Current expectation on Mac is to do nothing on Maximize.
1298 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1299 toplevel->GetRestoredBounds().ToString());
1300 #else
1301 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1302 toplevel->GetRestoredBounds().ToString());
1303 #endif
1304 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1305 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1307 toplevel->Restore();
1308 RunPendingMessages();
1309 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1310 toplevel->GetRestoredBounds().ToString());
1312 toplevel->SetFullscreen(true);
1313 RunPendingMessages();
1315 if (IsTestingSnowLeopard()) {
1316 // Fullscreen not implemented for Snow Leopard.
1317 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1318 toplevel->GetRestoredBounds().ToString());
1319 } else {
1320 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1321 toplevel->GetRestoredBounds().ToString());
1323 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1324 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1326 #endif
1328 // The key-event propagation from Widget happens differently on aura and
1329 // non-aura systems because of the difference in IME. So this test works only on
1330 // aura.
1331 TEST_F(WidgetTest, KeyboardInputEvent) {
1332 Widget* toplevel = CreateTopLevelPlatformWidget();
1333 View* container = toplevel->client_view();
1335 Textfield* textfield = new Textfield();
1336 textfield->SetText(base::ASCIIToUTF16("some text"));
1337 container->AddChildView(textfield);
1338 toplevel->Show();
1339 textfield->RequestFocus();
1341 // The press gets handled. The release doesn't have an effect.
1342 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1343 toplevel->OnKeyEvent(&backspace_p);
1344 EXPECT_TRUE(backspace_p.stopped_propagation());
1345 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1346 toplevel->OnKeyEvent(&backspace_r);
1347 EXPECT_FALSE(backspace_r.handled());
1349 toplevel->Close();
1352 // Verifies bubbles result in a focus lost when shown.
1353 // TODO(msw): this tests relies on focus, it needs to be in
1354 // interactive_ui_tests.
1355 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1356 // Create a widget, show and activate it and focus the contents view.
1357 View* contents_view = new View;
1358 contents_view->SetFocusable(true);
1359 Widget widget;
1360 Widget::InitParams init_params =
1361 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1362 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1363 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1364 #if !defined(OS_CHROMEOS)
1365 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1366 #endif
1367 widget.Init(init_params);
1368 widget.SetContentsView(contents_view);
1369 widget.Show();
1370 widget.Activate();
1371 contents_view->RequestFocus();
1372 EXPECT_TRUE(contents_view->HasFocus());
1374 // Show a bubble.
1375 BubbleDelegateView* bubble_delegate_view =
1376 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1377 bubble_delegate_view->SetFocusable(true);
1378 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1379 bubble_delegate_view->RequestFocus();
1381 // |contents_view_| should no longer have focus.
1382 EXPECT_FALSE(contents_view->HasFocus());
1383 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1385 bubble_delegate_view->GetWidget()->CloseNow();
1387 // Closing the bubble should result in focus going back to the contents view.
1388 EXPECT_TRUE(contents_view->HasFocus());
1391 class TestBubbleDelegateView : public BubbleDelegateView {
1392 public:
1393 TestBubbleDelegateView(View* anchor)
1394 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1395 reset_controls_called_(false) {}
1396 ~TestBubbleDelegateView() override {}
1398 bool ShouldShowCloseButton() const override {
1399 reset_controls_called_ = true;
1400 return true;
1403 mutable bool reset_controls_called_;
1406 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1407 Widget* anchor = CreateTopLevelPlatformWidget();
1408 anchor->Show();
1410 TestBubbleDelegateView* bubble_delegate =
1411 new TestBubbleDelegateView(anchor->client_view());
1412 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1413 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1414 bubble_widget->Show();
1415 bubble_widget->CloseNow();
1417 anchor->Hide();
1418 anchor->CloseNow();
1421 #if defined(OS_WIN)
1422 // Test to ensure that after minimize, view width is set to zero. This is only
1423 // the case for desktop widgets on Windows. Other platforms retain the window
1424 // size while minimized.
1425 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1426 // Create a widget.
1427 Widget widget;
1428 Widget::InitParams init_params =
1429 CreateParams(Widget::InitParams::TYPE_WINDOW);
1430 init_params.show_state = ui::SHOW_STATE_NORMAL;
1431 gfx::Rect initial_bounds(0, 0, 300, 400);
1432 init_params.bounds = initial_bounds;
1433 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1434 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1435 widget.Init(init_params);
1436 NonClientView* non_client_view = widget.non_client_view();
1437 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1438 non_client_view->SetFrameView(frame_view);
1439 // Setting the frame view doesn't do a layout, so force one.
1440 non_client_view->Layout();
1441 widget.Show();
1442 EXPECT_NE(0, frame_view->width());
1443 widget.Minimize();
1444 EXPECT_EQ(0, frame_view->width());
1446 #endif
1448 // Desktop native widget Aura tests are for non Chrome OS platforms.
1449 #if !defined(OS_CHROMEOS)
1450 // This class validates whether paints are received for a visible Widget.
1451 // To achieve this it overrides the Show and Close methods on the Widget class
1452 // and sets state whether subsequent paints are expected.
1453 class DesktopAuraTestValidPaintWidget : public views::Widget {
1454 public:
1455 DesktopAuraTestValidPaintWidget()
1456 : received_paint_(false),
1457 expect_paint_(true),
1458 received_paint_while_hidden_(false) {}
1460 ~DesktopAuraTestValidPaintWidget() override {}
1462 void InitForTest(Widget::InitParams create_params);
1464 void Show() override {
1465 expect_paint_ = true;
1466 views::Widget::Show();
1469 void Close() override {
1470 expect_paint_ = false;
1471 views::Widget::Close();
1474 void Hide() {
1475 expect_paint_ = false;
1476 views::Widget::Hide();
1479 void OnNativeWidgetPaint(const ui::PaintContext& context) override {
1480 received_paint_ = true;
1481 EXPECT_TRUE(expect_paint_);
1482 if (!expect_paint_)
1483 received_paint_while_hidden_ = true;
1484 views::Widget::OnNativeWidgetPaint(context);
1487 bool ReadReceivedPaintAndReset() {
1488 bool result = received_paint_;
1489 received_paint_ = false;
1490 return result;
1493 bool received_paint_while_hidden() const {
1494 return received_paint_while_hidden_;
1497 private:
1498 bool received_paint_;
1499 bool expect_paint_;
1500 bool received_paint_while_hidden_;
1502 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1505 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1506 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1507 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1508 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1509 Init(init_params);
1511 View* contents_view = new View;
1512 contents_view->SetFocusable(true);
1513 SetContentsView(contents_view);
1515 Show();
1516 Activate();
1519 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1520 DesktopAuraTestValidPaintWidget widget;
1521 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1522 RunPendingMessages();
1523 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1524 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1525 widget.Close();
1526 RunPendingMessages();
1527 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1528 EXPECT_FALSE(widget.received_paint_while_hidden());
1531 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1532 DesktopAuraTestValidPaintWidget widget;
1533 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1534 RunPendingMessages();
1535 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1536 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1537 widget.Hide();
1538 RunPendingMessages();
1539 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1540 EXPECT_FALSE(widget.received_paint_while_hidden());
1541 widget.Close();
1544 // Test to ensure that the aura Window's visiblity state is set to visible if
1545 // the underlying widget is hidden and then shown.
1546 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1547 // Create a widget.
1548 Widget widget;
1549 Widget::InitParams init_params =
1550 CreateParams(Widget::InitParams::TYPE_WINDOW);
1551 init_params.show_state = ui::SHOW_STATE_NORMAL;
1552 gfx::Rect initial_bounds(0, 0, 300, 400);
1553 init_params.bounds = initial_bounds;
1554 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1555 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1556 widget.Init(init_params);
1557 NonClientView* non_client_view = widget.non_client_view();
1558 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1559 non_client_view->SetFrameView(frame_view);
1561 widget.Show();
1562 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1563 widget.Hide();
1564 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1565 widget.Show();
1566 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1569 #endif // !defined(OS_CHROMEOS)
1571 // Tests that wheel events generated from scroll events are targetted to the
1572 // views under the cursor when the focused view does not processed them.
1573 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1574 EventCountView* cursor_view = new EventCountView;
1575 cursor_view->SetBounds(60, 0, 50, 40);
1577 Widget* widget = CreateTopLevelPlatformWidget();
1578 widget->GetRootView()->AddChildView(cursor_view);
1580 // Generate a scroll event on the cursor view.
1581 ui::ScrollEvent scroll(ui::ET_SCROLL,
1582 gfx::Point(65, 5),
1583 ui::EventTimeForNow(),
1585 0, 20,
1586 0, 20,
1588 widget->OnScrollEvent(&scroll);
1590 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1591 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1593 cursor_view->ResetCounts();
1595 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1596 gfx::Point(5, 5),
1597 ui::EventTimeForNow(),
1599 0, 20,
1600 0, 20,
1602 widget->OnScrollEvent(&scroll2);
1604 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1605 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1607 widget->CloseNow();
1610 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1611 // events are not dispatched to any view.
1612 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1613 EventCountView* noscroll_view = new EventCountView;
1614 EventCountView* scroll_view = new ScrollableEventCountView;
1616 noscroll_view->SetBounds(0, 0, 50, 40);
1617 scroll_view->SetBounds(60, 0, 40, 40);
1619 Widget* widget = CreateTopLevelPlatformWidget();
1620 widget->GetRootView()->AddChildView(noscroll_view);
1621 widget->GetRootView()->AddChildView(scroll_view);
1624 ui::GestureEvent begin(
1628 base::TimeDelta(),
1629 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1630 widget->OnGestureEvent(&begin);
1631 ui::GestureEvent update(
1635 base::TimeDelta(),
1636 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1637 widget->OnGestureEvent(&update);
1638 ui::GestureEvent end(25,
1641 base::TimeDelta(),
1642 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1643 widget->OnGestureEvent(&end);
1645 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1646 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1647 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1651 ui::GestureEvent begin(
1655 base::TimeDelta(),
1656 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1657 widget->OnGestureEvent(&begin);
1658 ui::GestureEvent update(
1662 base::TimeDelta(),
1663 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1664 widget->OnGestureEvent(&update);
1665 ui::GestureEvent end(85,
1668 base::TimeDelta(),
1669 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1670 widget->OnGestureEvent(&end);
1672 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1673 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1674 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1677 widget->CloseNow();
1680 // Tests that event-handlers installed on the RootView get triggered correctly.
1681 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1682 TEST_F(WidgetTest, EventHandlersOnRootView) {
1683 Widget* widget = CreateTopLevelNativeWidget();
1684 View* root_view = widget->GetRootView();
1686 scoped_ptr<EventCountView> view(new EventCountView());
1687 view->set_owned_by_client();
1688 view->SetBounds(0, 0, 20, 20);
1689 root_view->AddChildView(view.get());
1691 EventCountHandler h1;
1692 root_view->AddPreTargetHandler(&h1);
1694 EventCountHandler h2;
1695 root_view->AddPostTargetHandler(&h2);
1697 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1698 widget->Show();
1700 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1701 // bubble up the views hierarchy to be re-dispatched on the root view.
1702 ui::ScrollEvent scroll(ui::ET_SCROLL,
1703 gfx::Point(5, 5),
1704 ui::EventTimeForNow(),
1706 0, 20,
1707 0, 20,
1709 widget->OnScrollEvent(&scroll);
1710 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1711 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1712 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1714 // Unhandled scroll events are turned into wheel events and re-dispatched.
1715 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1716 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1717 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1719 h1.ResetCounts();
1720 view->ResetCounts();
1721 h2.ResetCounts();
1723 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1724 // should bubble up the views hierarchy to be re-dispatched on the root view.
1725 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1726 gfx::Point(5, 5),
1727 ui::EventTimeForNow(),
1729 0, 20,
1730 0, 20,
1732 widget->OnScrollEvent(&fling);
1733 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1734 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1735 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1737 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1738 // be turned into wheel events and re-dispatched.
1739 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1740 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1741 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1743 h1.ResetCounts();
1744 view->ResetCounts();
1745 h2.ResetCounts();
1747 // Change the handle mode of |view| so that events are marked as handled at
1748 // the target phase.
1749 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1751 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1752 // The events are handled at the target phase and should not reach the
1753 // post-target handler.
1754 ui::GestureEvent tap_down(5,
1757 ui::EventTimeForNow(),
1758 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1759 widget->OnGestureEvent(&tap_down);
1760 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1761 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1762 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1764 ui::GestureEvent tap_cancel(
1768 ui::EventTimeForNow(),
1769 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1770 widget->OnGestureEvent(&tap_cancel);
1771 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1772 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1773 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1775 h1.ResetCounts();
1776 view->ResetCounts();
1777 h2.ResetCounts();
1779 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1780 // and should not reach the post-target handler.
1781 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1782 gfx::Point(5, 5),
1783 ui::EventTimeForNow(),
1785 0, 20,
1786 0, 20,
1788 widget->OnScrollEvent(&consumed_scroll);
1789 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1790 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1791 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1793 // Handled scroll events are not turned into wheel events and re-dispatched.
1794 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1795 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1796 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1798 widget->CloseNow();
1801 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1802 Widget* widget = CreateTopLevelNativeWidget();
1803 View* root_view = widget->GetRootView();
1805 EventCountView* v1 = new EventCountView();
1806 v1->SetBounds(0, 0, 10, 10);
1807 root_view->AddChildView(v1);
1808 EventCountView* v2 = new EventCountView();
1809 v2->SetBounds(0, 10, 10, 10);
1810 root_view->AddChildView(v2);
1812 gfx::Point cursor_location(5, 5);
1813 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1814 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
1815 widget->OnMouseEvent(&move);
1817 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1818 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1820 delete v1;
1821 v2->SetBounds(0, 0, 10, 10);
1822 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1824 widget->SynthesizeMouseMoveEvent();
1825 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1827 widget->CloseNow();
1830 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1831 #if !defined(OS_MACOSX) || defined(USE_AURA)
1833 namespace {
1835 // ui::EventHandler which handles all mouse press events.
1836 class MousePressEventConsumer : public ui::EventHandler {
1837 public:
1838 MousePressEventConsumer() {}
1840 private:
1841 // ui::EventHandler:
1842 void OnMouseEvent(ui::MouseEvent* event) override {
1843 if (event->type() == ui::ET_MOUSE_PRESSED)
1844 event->SetHandled();
1847 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1850 } // namespace
1852 // Test that mouse presses and mouse releases are dispatched normally when a
1853 // touch is down.
1854 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1855 Widget* widget = CreateTopLevelNativeWidget();
1856 widget->Show();
1857 widget->SetSize(gfx::Size(300, 300));
1859 EventCountView* event_count_view = new EventCountView();
1860 event_count_view->SetBounds(0, 0, 300, 300);
1861 widget->GetRootView()->AddChildView(event_count_view);
1863 MousePressEventConsumer consumer;
1864 event_count_view->AddPostTargetHandler(&consumer);
1866 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1867 generator.PressTouch();
1868 generator.ClickLeftButton();
1870 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1871 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1873 widget->CloseNow();
1876 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1878 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1879 // is closed.
1880 TEST_F(WidgetTest, SingleWindowClosing) {
1881 TestDesktopWidgetDelegate delegate;
1882 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1883 EXPECT_EQ(0, delegate.window_closing_count());
1884 delegate.GetWidget()->CloseNow();
1885 EXPECT_EQ(1, delegate.window_closing_count());
1888 class WidgetWindowTitleTest : public WidgetTest {
1889 protected:
1890 void RunTest(bool desktop_native_widget) {
1891 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1892 Widget::InitParams init_params =
1893 CreateParams(Widget::InitParams::TYPE_WINDOW);
1894 widget->Init(init_params);
1896 #if !defined(OS_CHROMEOS)
1897 if (desktop_native_widget)
1898 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1899 #else
1900 DCHECK(!desktop_native_widget)
1901 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1902 #endif
1904 internal::NativeWidgetPrivate* native_widget =
1905 widget->native_widget_private();
1907 base::string16 empty;
1908 base::string16 s1(base::UTF8ToUTF16("Title1"));
1909 base::string16 s2(base::UTF8ToUTF16("Title2"));
1910 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1912 // The widget starts with no title, setting empty should not change
1913 // anything.
1914 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1915 // Setting the title to something non-empty should cause a change.
1916 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1917 // Setting the title to something else with the same length should cause a
1918 // change.
1919 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1920 // Setting the title to something else with a different length should cause
1921 // a change.
1922 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1923 // Setting the title to the same thing twice should not cause a change.
1924 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1926 widget->CloseNow();
1930 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1931 // Use the default NativeWidget.
1932 bool desktop_native_widget = false;
1933 RunTest(desktop_native_widget);
1936 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1937 #if !defined(OS_CHROMEOS)
1938 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1939 // Override to use a DesktopNativeWidget.
1940 bool desktop_native_widget = true;
1941 RunTest(desktop_native_widget);
1943 #endif // !OS_CHROMEOS
1945 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1946 Widget* widget = new Widget;
1947 Widget::InitParams params =
1948 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1949 widget->Init(params);
1951 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1953 widget->SetSize(gfx::Size(100, 100));
1954 widget->Show();
1956 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1958 WidgetDeletionObserver deletion_observer(widget);
1959 generator.ClickLeftButton();
1960 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1962 // Yay we did not crash!
1965 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1966 #if !defined(OS_MACOSX) || defined(USE_AURA)
1968 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1969 Widget* widget = new Widget;
1970 Widget::InitParams params =
1971 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1972 widget->Init(params);
1974 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1976 widget->SetSize(gfx::Size(100, 100));
1977 widget->Show();
1979 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1981 WidgetDeletionObserver deletion_observer(widget);
1982 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1983 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1985 // Yay we did not crash!
1988 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1990 // See description of RunGetNativeThemeFromDestructor() for details.
1991 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1992 public:
1993 GetNativeThemeFromDestructorView() {}
1994 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1996 View* GetContentsView() override { return this; }
1998 private:
1999 void VerifyNativeTheme() {
2000 ASSERT_TRUE(GetNativeTheme() != NULL);
2003 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
2006 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
2007 // crash. |is_first_run| is true if this is the first call. A return value of
2008 // true indicates this should be run again with a value of false.
2009 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
2010 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
2011 bool is_first_run) {
2012 bool needs_second_run = false;
2013 // Destroyed by CloseNow() below.
2014 Widget* widget = new Widget;
2015 Widget::InitParams params(in_params);
2016 // Deletes itself when the Widget is destroyed.
2017 params.delegate = new GetNativeThemeFromDestructorView;
2018 #if !defined(OS_CHROMEOS)
2019 if (is_first_run) {
2020 params.native_widget = new PlatformDesktopNativeWidget(widget);
2021 needs_second_run = true;
2023 #endif
2024 widget->Init(params);
2025 widget->CloseNow();
2026 return needs_second_run;
2029 // See description of RunGetNativeThemeFromDestructor() for details.
2030 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
2031 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2032 if (RunGetNativeThemeFromDestructor(params, true))
2033 RunGetNativeThemeFromDestructor(params, false);
2036 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
2037 // destroyed.
2038 class CloseDestroysWidget : public Widget {
2039 public:
2040 explicit CloseDestroysWidget(bool* destroyed)
2041 : destroyed_(destroyed) {
2044 ~CloseDestroysWidget() override {
2045 if (destroyed_) {
2046 *destroyed_ = true;
2047 base::MessageLoop::current()->QuitNow();
2051 void Detach() { destroyed_ = NULL; }
2053 private:
2054 // If non-null set to true from destructor.
2055 bool* destroyed_;
2057 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
2060 // An observer that registers that an animation has ended.
2061 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
2062 public:
2063 AnimationEndObserver() : animation_completed_(false) {}
2064 ~AnimationEndObserver() override {}
2066 bool animation_completed() const { return animation_completed_; }
2068 // ui::ImplicitAnimationObserver:
2069 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
2071 private:
2072 bool animation_completed_;
2074 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
2077 // An observer that registers the bounds of a widget on destruction.
2078 class WidgetBoundsObserver : public WidgetObserver {
2079 public:
2080 WidgetBoundsObserver() {}
2081 ~WidgetBoundsObserver() override {}
2083 gfx::Rect bounds() { return bounds_; }
2085 // WidgetObserver:
2086 void OnWidgetDestroying(Widget* widget) override {
2087 bounds_ = widget->GetWindowBoundsInScreen();
2090 private:
2091 gfx::Rect bounds_;
2093 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
2096 // Verifies Close() results in destroying.
2097 TEST_F(WidgetTest, CloseDestroys) {
2098 bool destroyed = false;
2099 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
2100 Widget::InitParams params =
2101 CreateParams(views::Widget::InitParams::TYPE_MENU);
2102 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
2103 #if !defined(OS_CHROMEOS)
2104 params.native_widget = new PlatformDesktopNativeWidget(widget);
2105 #endif
2106 widget->Init(params);
2107 widget->Show();
2108 widget->Hide();
2109 widget->Close();
2110 EXPECT_FALSE(destroyed);
2111 // Run the message loop as Close() asynchronously deletes.
2112 base::RunLoop().Run();
2113 EXPECT_TRUE(destroyed);
2114 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2115 if (!destroyed) {
2116 widget->Detach();
2117 widget->CloseNow();
2121 // Tests that killing a widget while animating it does not crash.
2122 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
2123 scoped_ptr<Widget> widget(new Widget);
2124 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2125 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2126 params.bounds = gfx::Rect(50, 50, 250, 250);
2127 widget->Init(params);
2128 AnimationEndObserver animation_observer;
2129 WidgetBoundsObserver widget_observer;
2130 gfx::Rect bounds(0, 0, 50, 50);
2132 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2133 // animating the movement.
2134 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
2135 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2136 ui::ScopedLayerAnimationSettings animation_settings(
2137 widget->GetLayer()->GetAnimator());
2138 animation_settings.AddObserver(&animation_observer);
2139 widget->AddObserver(&widget_observer);
2140 widget->Show();
2142 // Animate the bounds change.
2143 widget->SetBounds(bounds);
2144 widget.reset();
2145 EXPECT_FALSE(animation_observer.animation_completed());
2147 EXPECT_TRUE(animation_observer.animation_completed());
2148 EXPECT_EQ(widget_observer.bounds(), bounds);
2151 // Tests that we do not crash when a Widget is destroyed by going out of
2152 // scope (as opposed to being explicitly deleted by its NativeWidget).
2153 TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
2154 scoped_ptr<Widget> widget(new Widget);
2155 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2156 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2157 widget->Init(params);
2160 // Tests that we do not crash when a Widget is destroyed before it finishes
2161 // processing of pending input events in the message loop.
2162 TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
2163 scoped_ptr<Widget> widget(new Widget);
2164 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
2165 params.bounds = gfx::Rect(0, 0, 200, 200);
2166 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2167 widget->Init(params);
2168 widget->Show();
2170 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
2171 generator.MoveMouseTo(10, 10);
2173 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2174 #if defined(OS_MACOSX) && !defined(USE_AURA)
2175 generator.ClickLeftButton();
2176 #else
2177 generator.PressTouch();
2178 #endif
2179 widget.reset();
2182 // A view that consumes mouse-pressed event and gesture-tap-down events.
2183 class RootViewTestView : public View {
2184 public:
2185 RootViewTestView(): View() {}
2187 private:
2188 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
2190 void OnGestureEvent(ui::GestureEvent* event) override {
2191 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
2192 event->SetHandled();
2196 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2197 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2198 #if defined(OS_WIN)
2199 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2200 DISABLED_TestRootViewHandlersWhenHidden
2201 #else
2202 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2203 TestRootViewHandlersWhenHidden
2204 #endif
2205 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
2206 Widget* widget = CreateTopLevelNativeWidget();
2207 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2208 View* view = new RootViewTestView();
2209 view->SetBounds(0, 0, 300, 300);
2210 internal::RootView* root_view =
2211 static_cast<internal::RootView*>(widget->GetRootView());
2212 root_view->AddChildView(view);
2214 // Check RootView::mouse_pressed_handler_.
2215 widget->Show();
2216 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2217 gfx::Point click_location(45, 15);
2218 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
2219 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2220 ui::EF_LEFT_MOUSE_BUTTON);
2221 widget->OnMouseEvent(&press);
2222 EXPECT_EQ(view, GetMousePressedHandler(root_view));
2223 widget->Hide();
2224 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2226 // Check RootView::mouse_move_handler_.
2227 widget->Show();
2228 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2229 gfx::Point move_location(45, 15);
2230 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
2231 ui::EventTimeForNow(), 0, 0);
2232 widget->OnMouseEvent(&move);
2233 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
2234 widget->Hide();
2235 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2237 // Check RootView::gesture_handler_.
2238 widget->Show();
2239 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2240 ui::GestureEvent tap_down(15,
2243 base::TimeDelta(),
2244 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2245 widget->OnGestureEvent(&tap_down);
2246 EXPECT_EQ(view, GetGestureHandler(root_view));
2247 widget->Hide();
2248 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2250 widget->Close();
2253 // Convenience to make constructing a GestureEvent simpler.
2254 class GestureEventForTest : public ui::GestureEvent {
2255 public:
2256 GestureEventForTest(ui::EventType type, int x, int y)
2257 : GestureEvent(x,
2260 base::TimeDelta(),
2261 ui::GestureEventDetails(type)) {}
2263 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2264 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2267 // Tests that the |gesture_handler_| member in RootView is always NULL
2268 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2269 // the release of the final touch point on the screen, but that
2270 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2271 // point do not modify |gesture_handler_|.
2272 TEST_F(WidgetTest, GestureEndEvents) {
2273 Widget* widget = CreateTopLevelNativeWidget();
2274 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2275 EventCountView* view = new EventCountView();
2276 view->SetBounds(0, 0, 300, 300);
2277 internal::RootView* root_view =
2278 static_cast<internal::RootView*>(widget->GetRootView());
2279 root_view->AddChildView(view);
2280 widget->Show();
2282 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2283 // the gesture handler.
2284 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2285 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2286 widget->OnGestureEvent(&end);
2287 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2289 // Change the handle mode of |view| to indicate that it would like
2290 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2291 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2292 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2293 widget->OnGestureEvent(&tap);
2294 EXPECT_TRUE(tap.handled());
2295 EXPECT_EQ(view, GetGestureHandler(root_view));
2297 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2298 // corresponding to a second touch point, but should be reset to NULL by a
2299 // ui::ET_GESTURE_END corresponding to the final touch point.
2300 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2301 details.set_touch_points(2);
2302 GestureEventForTest end_second_touch_point(details, 15, 15);
2303 widget->OnGestureEvent(&end_second_touch_point);
2304 EXPECT_EQ(view, GetGestureHandler(root_view));
2306 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2307 widget->OnGestureEvent(&end);
2308 EXPECT_TRUE(end.handled());
2309 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2311 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2312 // mode of |view| to indicate that it does not want to handle any
2313 // further events.
2314 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2315 widget->OnGestureEvent(&tap);
2316 EXPECT_TRUE(tap.handled());
2317 EXPECT_EQ(view, GetGestureHandler(root_view));
2318 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2320 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2321 // corresponding to a second touch point, but should be reset to NULL by a
2322 // ui::ET_GESTURE_END corresponding to the final touch point.
2323 end_second_touch_point = GestureEventForTest(details, 15, 15);
2324 widget->OnGestureEvent(&end_second_touch_point);
2325 EXPECT_EQ(view, GetGestureHandler(root_view));
2327 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2328 widget->OnGestureEvent(&end);
2329 EXPECT_FALSE(end.handled());
2330 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2332 widget->Close();
2335 // Tests that gesture events which should not be processed (because
2336 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2337 // dispatched to any views.
2338 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2339 Widget* widget = CreateTopLevelNativeWidget();
2340 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2342 // Define a hierarchy of four views (coordinates are in
2343 // their parent coordinate space).
2344 // v1 (0, 0, 300, 300)
2345 // v2 (0, 0, 100, 100)
2346 // v3 (0, 0, 50, 50)
2347 // v4(0, 0, 10, 10)
2348 EventCountView* v1 = new EventCountView();
2349 v1->SetBounds(0, 0, 300, 300);
2350 EventCountView* v2 = new EventCountView();
2351 v2->SetBounds(0, 0, 100, 100);
2352 EventCountView* v3 = new EventCountView();
2353 v3->SetBounds(0, 0, 50, 50);
2354 EventCountView* v4 = new EventCountView();
2355 v4->SetBounds(0, 0, 10, 10);
2356 internal::RootView* root_view =
2357 static_cast<internal::RootView*>(widget->GetRootView());
2358 root_view->AddChildView(v1);
2359 v1->AddChildView(v2);
2360 v2->AddChildView(v3);
2361 v3->AddChildView(v4);
2363 widget->Show();
2365 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2366 // they should be marked as handled by OnEventProcessingStarted().
2367 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2368 widget->OnGestureEvent(&begin);
2369 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2370 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2371 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2372 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2373 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2374 EXPECT_TRUE(begin.handled());
2375 v1->ResetCounts();
2376 v2->ResetCounts();
2377 v3->ResetCounts();
2378 v4->ResetCounts();
2380 // ui::ET_GESTURE_END events should not be seen by any view when there is
2381 // no default gesture handler set, but they should be marked as handled by
2382 // OnEventProcessingStarted().
2383 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2384 widget->OnGestureEvent(&end);
2385 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2386 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2387 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2388 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2389 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2390 EXPECT_TRUE(end.handled());
2391 v1->ResetCounts();
2392 v2->ResetCounts();
2393 v3->ResetCounts();
2394 v4->ResetCounts();
2396 // ui::ET_GESTURE_END events not corresponding to the release of the
2397 // final touch point should never be seen by any view, but they should
2398 // be marked as handled by OnEventProcessingStarted().
2399 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2400 details.set_touch_points(2);
2401 GestureEventForTest end_second_touch_point(details, 5, 5);
2402 widget->OnGestureEvent(&end_second_touch_point);
2403 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2404 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2405 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2406 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2407 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2408 EXPECT_TRUE(end_second_touch_point.handled());
2409 v1->ResetCounts();
2410 v2->ResetCounts();
2411 v3->ResetCounts();
2412 v4->ResetCounts();
2414 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2415 // there is no default gesture handler set, but they should be marked as
2416 // handled by OnEventProcessingStarted().
2417 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2418 widget->OnGestureEvent(&scroll_update);
2419 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2420 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2421 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2422 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2423 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2424 EXPECT_TRUE(scroll_update.handled());
2425 v1->ResetCounts();
2426 v2->ResetCounts();
2427 v3->ResetCounts();
2428 v4->ResetCounts();
2430 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2431 // there is no default gesture handler set, but they should be marked as
2432 // handled by OnEventProcessingStarted().
2433 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2434 widget->OnGestureEvent(&scroll_end);
2435 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2436 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2437 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2438 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2439 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2440 EXPECT_TRUE(scroll_end.handled());
2441 v1->ResetCounts();
2442 v2->ResetCounts();
2443 v3->ResetCounts();
2444 v4->ResetCounts();
2446 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2447 // there is no default gesture handler set, but they should be marked as
2448 // handled by OnEventProcessingStarted().
2449 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2450 widget->OnGestureEvent(&scroll_fling_start);
2451 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2452 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2453 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2454 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2455 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2456 EXPECT_TRUE(scroll_fling_start.handled());
2457 v1->ResetCounts();
2458 v2->ResetCounts();
2459 v3->ResetCounts();
2460 v4->ResetCounts();
2462 widget->Close();
2465 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2466 // in a view hierarchy and that the default gesture handler in RootView is set
2467 // correctly.
2468 TEST_F(WidgetTest, GestureEventDispatch) {
2469 Widget* widget = CreateTopLevelNativeWidget();
2470 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2472 // Define a hierarchy of four views (coordinates are in
2473 // their parent coordinate space).
2474 // v1 (0, 0, 300, 300)
2475 // v2 (0, 0, 100, 100)
2476 // v3 (0, 0, 50, 50)
2477 // v4(0, 0, 10, 10)
2478 EventCountView* v1 = new EventCountView();
2479 v1->SetBounds(0, 0, 300, 300);
2480 EventCountView* v2 = new EventCountView();
2481 v2->SetBounds(0, 0, 100, 100);
2482 EventCountView* v3 = new EventCountView();
2483 v3->SetBounds(0, 0, 50, 50);
2484 EventCountView* v4 = new EventCountView();
2485 v4->SetBounds(0, 0, 10, 10);
2486 internal::RootView* root_view =
2487 static_cast<internal::RootView*>(widget->GetRootView());
2488 root_view->AddChildView(v1);
2489 v1->AddChildView(v2);
2490 v2->AddChildView(v3);
2491 v3->AddChildView(v4);
2493 widget->Show();
2495 // No gesture handler is set in the root view and none of the views in the
2496 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2497 // event should be dispatched to all views in the hierarchy, the gesture
2498 // handler should remain unset, and the event should remain unhandled.
2499 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2500 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2501 widget->OnGestureEvent(&tap);
2502 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2503 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2504 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2505 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2506 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2507 EXPECT_FALSE(tap.handled());
2509 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2510 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2511 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2512 // and the event should be marked as handled.
2513 v1->ResetCounts();
2514 v2->ResetCounts();
2515 v3->ResetCounts();
2516 v4->ResetCounts();
2517 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2518 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2519 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2520 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2521 widget->OnGestureEvent(&tap);
2522 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2523 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2524 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2525 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2526 EXPECT_EQ(v3, GetGestureHandler(root_view));
2527 EXPECT_TRUE(tap.handled());
2529 // The gesture handler is set to |v3| and all views handle all gesture event
2530 // types. In this case subsequent gesture events should only be dispatched to
2531 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2532 v1->ResetCounts();
2533 v2->ResetCounts();
2534 v3->ResetCounts();
2535 v4->ResetCounts();
2536 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2537 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2538 widget->OnGestureEvent(&tap);
2539 EXPECT_TRUE(tap.handled());
2540 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2541 widget->OnGestureEvent(&show_press);
2542 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2543 widget->OnGestureEvent(&tap);
2544 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2545 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2546 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2547 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2548 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2549 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2550 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2551 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2552 EXPECT_TRUE(tap.handled());
2553 EXPECT_TRUE(show_press.handled());
2554 EXPECT_EQ(v3, GetGestureHandler(root_view));
2556 // The gesture handler is set to |v3|, but |v3| does not handle
2557 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2558 // only to |v3|, but the event should remain unhandled. The gesture handler
2559 // should remain as |v3|.
2560 v1->ResetCounts();
2561 v2->ResetCounts();
2562 v3->ResetCounts();
2563 v4->ResetCounts();
2564 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2565 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2566 widget->OnGestureEvent(&tap);
2567 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2568 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2569 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2570 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2571 EXPECT_FALSE(tap.handled());
2572 EXPECT_EQ(v3, GetGestureHandler(root_view));
2574 widget->Close();
2577 // Tests that gesture scroll events will change the default gesture handler in
2578 // RootView if the current handler to which they are dispatched does not handle
2579 // gesture scroll events.
2580 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2581 Widget* widget = CreateTopLevelNativeWidget();
2582 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2584 // Define a hierarchy of four views (coordinates are in
2585 // their parent coordinate space).
2586 // v1 (0, 0, 300, 300)
2587 // v2 (0, 0, 100, 100)
2588 // v3 (0, 0, 50, 50)
2589 // v4(0, 0, 10, 10)
2590 EventCountView* v1 = new EventCountView();
2591 v1->SetBounds(0, 0, 300, 300);
2592 EventCountView* v2 = new EventCountView();
2593 v2->SetBounds(0, 0, 100, 100);
2594 EventCountView* v3 = new EventCountView();
2595 v3->SetBounds(0, 0, 50, 50);
2596 EventCountView* v4 = new EventCountView();
2597 v4->SetBounds(0, 0, 10, 10);
2598 internal::RootView* root_view =
2599 static_cast<internal::RootView*>(widget->GetRootView());
2600 root_view->AddChildView(v1);
2601 v1->AddChildView(v2);
2602 v2->AddChildView(v3);
2603 v3->AddChildView(v4);
2605 widget->Show();
2607 // Change the handle mode of |v3| to indicate that it would like to handle
2608 // gesture events.
2609 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2611 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2612 // should bubble up the views hierarchy until it reaches the first view
2613 // that will handle it (|v3|) and then sets the handler to |v3|.
2614 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2615 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2616 widget->OnGestureEvent(&tap_down);
2617 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2618 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2619 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2620 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2621 EXPECT_EQ(v3, GetGestureHandler(root_view));
2622 EXPECT_TRUE(tap_down.handled());
2623 v1->ResetCounts();
2624 v2->ResetCounts();
2625 v3->ResetCounts();
2626 v4->ResetCounts();
2628 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2629 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2630 widget->OnGestureEvent(&tap_cancel);
2631 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2632 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2633 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2634 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2635 EXPECT_EQ(v3, GetGestureHandler(root_view));
2636 EXPECT_TRUE(tap_cancel.handled());
2637 v1->ResetCounts();
2638 v2->ResetCounts();
2639 v3->ResetCounts();
2640 v4->ResetCounts();
2642 // Change the handle mode of |v3| to indicate that it would no longer like
2643 // to handle events, and change the mode of |v1| to indicate that it would
2644 // like to handle events.
2645 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2646 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2648 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2649 // handler (|v3|) does not handle scroll events, the event should bubble up
2650 // the views hierarchy until it reaches the first view that will handle
2651 // it (|v1|) and then sets the handler to |v1|.
2652 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2653 widget->OnGestureEvent(&scroll_begin);
2654 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2655 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2656 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2657 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2658 EXPECT_EQ(v1, GetGestureHandler(root_view));
2659 EXPECT_TRUE(scroll_begin.handled());
2660 v1->ResetCounts();
2661 v2->ResetCounts();
2662 v3->ResetCounts();
2663 v4->ResetCounts();
2665 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2666 // directly.
2667 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2668 widget->OnGestureEvent(&scroll_update);
2669 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2670 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2671 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2672 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2673 EXPECT_EQ(v1, GetGestureHandler(root_view));
2674 EXPECT_TRUE(scroll_update.handled());
2675 v1->ResetCounts();
2676 v2->ResetCounts();
2677 v3->ResetCounts();
2678 v4->ResetCounts();
2680 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2681 // directly and should not reset the gesture handler.
2682 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2683 widget->OnGestureEvent(&scroll_end);
2684 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2685 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2686 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2687 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2688 EXPECT_EQ(v1, GetGestureHandler(root_view));
2689 EXPECT_TRUE(scroll_end.handled());
2690 v1->ResetCounts();
2691 v2->ResetCounts();
2692 v3->ResetCounts();
2693 v4->ResetCounts();
2695 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2696 // still be dispatched to |v1| directly.
2697 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2698 widget->OnGestureEvent(&pinch_begin);
2699 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2700 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2701 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2702 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2703 EXPECT_EQ(v1, GetGestureHandler(root_view));
2704 EXPECT_TRUE(pinch_begin.handled());
2705 v1->ResetCounts();
2706 v2->ResetCounts();
2707 v3->ResetCounts();
2708 v4->ResetCounts();
2710 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2711 // set the gesture handler to NULL.
2712 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2713 widget->OnGestureEvent(&end);
2714 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2715 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2716 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2717 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2718 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2719 EXPECT_TRUE(end.handled());
2721 widget->Close();
2724 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2725 // that when a gesture event bubbles up a View hierarchy, the location
2726 // of a gesture event seen by each View is in the local coordinate space
2727 // of that View.
2728 class GestureLocationView : public EventCountView {
2729 public:
2730 GestureLocationView() {}
2731 ~GestureLocationView() override {}
2733 void set_expected_location(gfx::Point expected_location) {
2734 expected_location_ = expected_location;
2737 // EventCountView:
2738 void OnGestureEvent(ui::GestureEvent* event) override {
2739 EventCountView::OnGestureEvent(event);
2741 // Verify that the location of |event| is in the local coordinate
2742 // space of |this|.
2743 EXPECT_EQ(expected_location_, event->location());
2746 private:
2747 // The expected location of a gesture event dispatched to |this|.
2748 gfx::Point expected_location_;
2750 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2753 // Verifies that the location of a gesture event is always in the local
2754 // coordinate space of the View receiving the event while bubbling.
2755 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2756 Widget* widget = CreateTopLevelNativeWidget();
2757 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2759 // Define a hierarchy of three views (coordinates shown below are in the
2760 // coordinate space of the root view, but the coordinates used for
2761 // SetBounds() are in their parent coordinate space).
2762 // v1 (50, 50, 150, 150)
2763 // v2 (100, 70, 50, 80)
2764 // v3 (120, 100, 10, 10)
2765 GestureLocationView* v1 = new GestureLocationView();
2766 v1->SetBounds(50, 50, 150, 150);
2767 GestureLocationView* v2 = new GestureLocationView();
2768 v2->SetBounds(50, 20, 50, 80);
2769 GestureLocationView* v3 = new GestureLocationView();
2770 v3->SetBounds(20, 30, 10, 10);
2771 internal::RootView* root_view =
2772 static_cast<internal::RootView*>(widget->GetRootView());
2773 root_view->AddChildView(v1);
2774 v1->AddChildView(v2);
2775 v2->AddChildView(v3);
2777 widget->Show();
2779 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2780 // This event is contained within all of |v1|, |v2|, and |v3|.
2781 gfx::Point location_in_root(125, 105);
2782 GestureEventForTest tap(
2783 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2785 // Calculate the location of the event in the local coordinate spaces
2786 // of each of the views.
2787 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2788 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2789 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2790 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2791 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2792 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2794 // Dispatch the event. When each view receives the event, its location should
2795 // be in the local coordinate space of that view (see the check made by
2796 // GestureLocationView). After dispatch is complete the event's location
2797 // should be in the root coordinate space.
2798 v1->set_expected_location(location_in_v1);
2799 v2->set_expected_location(location_in_v2);
2800 v3->set_expected_location(location_in_v3);
2801 widget->OnGestureEvent(&tap);
2802 EXPECT_EQ(location_in_root, tap.location());
2804 // Verify that each view did in fact see the event.
2805 EventCountView* view1 = v1;
2806 EventCountView* view2 = v2;
2807 EventCountView* view3 = v3;
2808 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2809 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2810 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2812 widget->Close();
2815 // Verifies that disabled views are permitted to be set as the default gesture
2816 // handler in RootView. Also verifies that gesture events targeted to a disabled
2817 // view are not actually dispatched to the view, but are still marked as
2818 // handled.
2819 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2820 Widget* widget = CreateTopLevelNativeWidget();
2821 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2823 // Define a hierarchy of four views (coordinates are in
2824 // their parent coordinate space).
2825 // v1 (0, 0, 300, 300)
2826 // v2 (0, 0, 100, 100)
2827 // v3 (0, 0, 50, 50)
2828 // v4(0, 0, 10, 10)
2829 EventCountView* v1 = new EventCountView();
2830 v1->SetBounds(0, 0, 300, 300);
2831 EventCountView* v2 = new EventCountView();
2832 v2->SetBounds(0, 0, 100, 100);
2833 EventCountView* v3 = new EventCountView();
2834 v3->SetBounds(0, 0, 50, 50);
2835 EventCountView* v4 = new EventCountView();
2836 v4->SetBounds(0, 0, 10, 10);
2837 internal::RootView* root_view =
2838 static_cast<internal::RootView*>(widget->GetRootView());
2839 root_view->AddChildView(v1);
2840 v1->AddChildView(v2);
2841 v2->AddChildView(v3);
2842 v3->AddChildView(v4);
2844 widget->Show();
2846 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2847 // disabled.
2848 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2849 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2850 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2851 v3->SetEnabled(false);
2853 // No gesture handler is set in the root view. In this case the tap event
2854 // should be dispatched only to |v4|, the gesture handler should be set to
2855 // |v3|, and the event should be marked as handled.
2856 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2857 widget->OnGestureEvent(&tap);
2858 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2859 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2860 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2861 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2862 EXPECT_EQ(v3, GetGestureHandler(root_view));
2863 EXPECT_TRUE(tap.handled());
2864 v1->ResetCounts();
2865 v2->ResetCounts();
2866 v3->ResetCounts();
2867 v4->ResetCounts();
2869 // A subsequent gesture event should be marked as handled but not dispatched.
2870 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2871 widget->OnGestureEvent(&tap);
2872 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2873 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2874 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2875 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2876 EXPECT_EQ(v3, GetGestureHandler(root_view));
2877 EXPECT_TRUE(tap.handled());
2878 v1->ResetCounts();
2879 v2->ResetCounts();
2880 v3->ResetCounts();
2881 v4->ResetCounts();
2883 // A GESTURE_END should reset the default gesture handler to NULL. It should
2884 // also not be dispatched to |v3| but still marked as handled.
2885 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2886 widget->OnGestureEvent(&end);
2887 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2888 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2889 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2890 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2891 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2892 EXPECT_TRUE(end.handled());
2893 v1->ResetCounts();
2894 v2->ResetCounts();
2895 v3->ResetCounts();
2896 v4->ResetCounts();
2898 // Change the handle mode of |v3| to indicate that it would no longer like
2899 // to handle events which are dispatched to it.
2900 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2902 // No gesture handler is set in the root view. In this case the tap event
2903 // should be dispatched only to |v4| and the event should be marked as
2904 // handled. Furthermore, the gesture handler should be set to
2905 // |v3|; even though |v3| does not explicitly handle events, it is a
2906 // valid target for the tap event because it is disabled.
2907 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2908 widget->OnGestureEvent(&tap);
2909 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2910 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2911 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2912 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2913 EXPECT_EQ(v3, GetGestureHandler(root_view));
2914 EXPECT_TRUE(tap.handled());
2915 v1->ResetCounts();
2916 v2->ResetCounts();
2917 v3->ResetCounts();
2918 v4->ResetCounts();
2920 // A GESTURE_END should reset the default gesture handler to NULL. It should
2921 // also not be dispatched to |v3| but still marked as handled.
2922 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2923 widget->OnGestureEvent(&end);
2924 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2925 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2926 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2927 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2928 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2929 EXPECT_TRUE(end.handled());
2931 widget->Close();
2934 // Test the result of Widget::GetAllChildWidgets().
2935 TEST_F(WidgetTest, GetAllChildWidgets) {
2936 // Create the following widget hierarchy:
2938 // toplevel
2939 // +-- w1
2940 // +-- w11
2941 // +-- w2
2942 // +-- w21
2943 // +-- w22
2944 Widget* toplevel = CreateTopLevelPlatformWidget();
2945 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2946 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2947 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2948 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2949 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2951 std::set<Widget*> expected;
2952 expected.insert(toplevel);
2953 expected.insert(w1);
2954 expected.insert(w11);
2955 expected.insert(w2);
2956 expected.insert(w21);
2957 expected.insert(w22);
2959 std::set<Widget*> widgets;
2960 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2962 EXPECT_EQ(expected.size(), widgets.size());
2963 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2964 toplevel->CloseNow();
2967 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2968 // a vector.
2969 class DestroyedTrackingView : public View {
2970 public:
2971 DestroyedTrackingView(const std::string& name,
2972 std::vector<std::string>* add_to)
2973 : name_(name),
2974 add_to_(add_to) {
2977 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2979 private:
2980 const std::string name_;
2981 std::vector<std::string>* add_to_;
2983 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2986 class WidgetChildDestructionTest : public WidgetTest {
2987 public:
2988 WidgetChildDestructionTest() {}
2990 // Creates a top level and a child, destroys the child and verifies the views
2991 // of the child are destroyed before the views of the parent.
2992 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2993 bool child_has_desktop_native_widget_aura) {
2994 // When a View is destroyed its name is added here.
2995 std::vector<std::string> destroyed;
2997 Widget* top_level = new Widget;
2998 Widget::InitParams params =
2999 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
3000 #if !defined(OS_CHROMEOS)
3001 if (top_level_has_desktop_native_widget_aura)
3002 params.native_widget = new PlatformDesktopNativeWidget(top_level);
3003 #endif
3004 top_level->Init(params);
3005 top_level->GetRootView()->AddChildView(
3006 new DestroyedTrackingView("parent", &destroyed));
3007 top_level->Show();
3009 Widget* child = new Widget;
3010 Widget::InitParams child_params =
3011 CreateParams(views::Widget::InitParams::TYPE_POPUP);
3012 child_params.parent = top_level->GetNativeView();
3013 #if !defined(OS_CHROMEOS)
3014 if (child_has_desktop_native_widget_aura)
3015 child_params.native_widget = new PlatformDesktopNativeWidget(child);
3016 #endif
3017 child->Init(child_params);
3018 child->GetRootView()->AddChildView(
3019 new DestroyedTrackingView("child", &destroyed));
3020 child->Show();
3022 // Should trigger destruction of the child too.
3023 top_level->native_widget_private()->CloseNow();
3025 // Child should be destroyed first.
3026 ASSERT_EQ(2u, destroyed.size());
3027 EXPECT_EQ("child", destroyed[0]);
3028 EXPECT_EQ("parent", destroyed[1]);
3031 private:
3032 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
3035 #if !defined(OS_CHROMEOS)
3036 // See description of RunDestroyChildWidgetsTest(). Parent uses
3037 // DesktopNativeWidgetAura.
3038 TEST_F(WidgetChildDestructionTest,
3039 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
3040 RunDestroyChildWidgetsTest(true, false);
3043 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
3044 // DesktopNativeWidgetAura.
3045 TEST_F(WidgetChildDestructionTest,
3046 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
3047 RunDestroyChildWidgetsTest(true, true);
3049 #endif // !defined(OS_CHROMEOS)
3051 // See description of RunDestroyChildWidgetsTest().
3052 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
3053 RunDestroyChildWidgetsTest(false, false);
3056 #if !defined(OS_CHROMEOS)
3057 // Provides functionality to create a window modal dialog.
3058 class ModalDialogDelegate : public DialogDelegateView {
3059 public:
3060 ModalDialogDelegate() {}
3061 ~ModalDialogDelegate() override {}
3063 // WidgetDelegate overrides.
3064 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
3066 private:
3067 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
3070 // This test verifies that whether mouse events when a modal dialog is
3071 // displayed are eaten or recieved by the dialog.
3072 TEST_F(WidgetTest, WindowMouseModalityTest) {
3073 // Create a top level widget.
3074 Widget top_level_widget;
3075 Widget::InitParams init_params =
3076 CreateParams(Widget::InitParams::TYPE_WINDOW);
3077 init_params.show_state = ui::SHOW_STATE_NORMAL;
3078 gfx::Rect initial_bounds(0, 0, 500, 500);
3079 init_params.bounds = initial_bounds;
3080 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3081 init_params.native_widget =
3082 new PlatformDesktopNativeWidget(&top_level_widget);
3083 top_level_widget.Init(init_params);
3084 top_level_widget.Show();
3085 EXPECT_TRUE(top_level_widget.IsVisible());
3087 // Create a view and validate that a mouse moves makes it to the view.
3088 EventCountView* widget_view = new EventCountView();
3089 widget_view->SetBounds(0, 0, 10, 10);
3090 top_level_widget.GetRootView()->AddChildView(widget_view);
3092 gfx::Point cursor_location_main(5, 5);
3093 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main,
3094 cursor_location_main, ui::EventTimeForNow(),
3095 ui::EF_NONE, ui::EF_NONE);
3096 ui::EventDispatchDetails details =
3097 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
3098 ASSERT_FALSE(details.dispatcher_destroyed);
3100 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
3101 widget_view->ResetCounts();
3103 // Create a modal dialog and validate that a mouse down message makes it to
3104 // the main view within the dialog.
3106 // This instance will be destroyed when the dialog is destroyed.
3107 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3109 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3110 dialog_delegate, NULL, top_level_widget.GetNativeView());
3111 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3112 EventCountView* dialog_widget_view = new EventCountView();
3113 dialog_widget_view->SetBounds(0, 0, 50, 50);
3114 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
3115 modal_dialog_widget->Show();
3116 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3118 gfx::Point cursor_location_dialog(100, 100);
3119 ui::MouseEvent mouse_down_dialog(
3120 ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog,
3121 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
3122 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
3123 &mouse_down_dialog);
3124 ASSERT_FALSE(details.dispatcher_destroyed);
3125 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
3127 // Send a mouse move message to the main window. It should not be received by
3128 // the main window as the modal dialog is still active.
3129 gfx::Point cursor_location_main2(6, 6);
3130 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2,
3131 cursor_location_main2, ui::EventTimeForNow(),
3132 ui::EF_NONE, ui::EF_NONE);
3133 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
3134 &mouse_down_main);
3135 ASSERT_FALSE(details.dispatcher_destroyed);
3136 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
3138 modal_dialog_widget->CloseNow();
3139 top_level_widget.CloseNow();
3142 // Verifies nativeview visbility matches that of Widget visibility when
3143 // SetFullscreen is invoked.
3144 TEST_F(WidgetTest, FullscreenStatePropagated) {
3145 Widget::InitParams init_params =
3146 CreateParams(Widget::InitParams::TYPE_WINDOW);
3147 init_params.show_state = ui::SHOW_STATE_NORMAL;
3148 init_params.bounds = gfx::Rect(0, 0, 500, 500);
3149 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3152 Widget top_level_widget;
3153 top_level_widget.Init(init_params);
3154 top_level_widget.SetFullscreen(true);
3155 EXPECT_EQ(top_level_widget.IsVisible(),
3156 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3157 top_level_widget.CloseNow();
3159 #if !defined(OS_CHROMEOS)
3161 Widget top_level_widget;
3162 init_params.native_widget =
3163 new PlatformDesktopNativeWidget(&top_level_widget);
3164 top_level_widget.Init(init_params);
3165 top_level_widget.SetFullscreen(true);
3166 EXPECT_EQ(top_level_widget.IsVisible(),
3167 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3168 top_level_widget.CloseNow();
3170 #endif
3172 #if defined(OS_WIN)
3174 // Tests whether we can activate the top level widget when a modal dialog is
3175 // active.
3176 TEST_F(WidgetTest, WindowModalityActivationTest) {
3177 TestDesktopWidgetDelegate widget_delegate;
3178 widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
3180 Widget* top_level_widget = widget_delegate.GetWidget();
3181 top_level_widget->Show();
3182 EXPECT_TRUE(top_level_widget->IsVisible());
3184 HWND win32_window = views::HWNDForWidget(top_level_widget);
3185 EXPECT_TRUE(::IsWindow(win32_window));
3187 // This instance will be destroyed when the dialog is destroyed.
3188 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3190 // We should be able to activate the window even if the WidgetDelegate
3191 // says no, when a modal dialog is active.
3192 widget_delegate.set_can_activate(false);
3194 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3195 dialog_delegate, NULL, top_level_widget->GetNativeView());
3196 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3197 modal_dialog_widget->Show();
3198 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3200 LRESULT activate_result = ::SendMessage(
3201 win32_window,
3202 WM_MOUSEACTIVATE,
3203 reinterpret_cast<WPARAM>(win32_window),
3204 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
3205 EXPECT_EQ(activate_result, MA_ACTIVATE);
3207 modal_dialog_widget->CloseNow();
3209 #endif // defined(OS_WIN)
3210 #endif // !defined(OS_CHROMEOS)
3212 namespace {
3214 class FullscreenAwareFrame : public views::NonClientFrameView {
3215 public:
3216 explicit FullscreenAwareFrame(views::Widget* widget)
3217 : widget_(widget), fullscreen_layout_called_(false) {}
3218 ~FullscreenAwareFrame() override {}
3220 // views::NonClientFrameView overrides:
3221 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3222 gfx::Rect GetWindowBoundsForClientBounds(
3223 const gfx::Rect& client_bounds) const override {
3224 return gfx::Rect();
3226 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3227 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3228 void ResetWindowControls() override {}
3229 void UpdateWindowIcon() override {}
3230 void UpdateWindowTitle() override {}
3231 void SizeConstraintsChanged() override {}
3233 // views::View overrides:
3234 void Layout() override {
3235 if (widget_->IsFullscreen())
3236 fullscreen_layout_called_ = true;
3239 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3241 private:
3242 views::Widget* widget_;
3243 bool fullscreen_layout_called_;
3245 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3248 } // namespace
3250 // Tests that frame Layout is called when a widget goes fullscreen without
3251 // changing its size or title.
3252 TEST_F(WidgetTest, FullscreenFrameLayout) {
3253 Widget* widget = CreateTopLevelPlatformWidget();
3254 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3255 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3257 widget->Maximize();
3258 RunPendingMessages();
3260 EXPECT_FALSE(frame->fullscreen_layout_called());
3261 widget->SetFullscreen(true);
3262 widget->Show();
3263 RunPendingMessages();
3265 if (IsTestingSnowLeopard()) {
3266 // Fullscreen is currently ignored on Snow Leopard.
3267 EXPECT_FALSE(frame->fullscreen_layout_called());
3268 } else {
3269 EXPECT_TRUE(frame->fullscreen_layout_called());
3272 widget->CloseNow();
3275 #if !defined(OS_CHROMEOS)
3276 namespace {
3278 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3279 // OnWindowDestroying.
3280 class IsActiveFromDestroyObserver : public WidgetObserver {
3281 public:
3282 IsActiveFromDestroyObserver() {}
3283 ~IsActiveFromDestroyObserver() override {}
3284 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3286 private:
3287 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3290 } // namespace
3292 // Verifies Widget::IsActive() invoked from
3293 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3294 TEST_F(WidgetTest, IsActiveFromDestroy) {
3295 // Create two widgets, one a child of the other.
3296 IsActiveFromDestroyObserver observer;
3297 Widget parent_widget;
3298 Widget::InitParams parent_params =
3299 CreateParams(Widget::InitParams::TYPE_POPUP);
3300 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3301 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3302 parent_widget.Init(parent_params);
3303 parent_widget.Show();
3305 Widget child_widget;
3306 Widget::InitParams child_params =
3307 CreateParams(Widget::InitParams::TYPE_POPUP);
3308 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3309 child_params.context = parent_widget.GetNativeWindow();
3310 child_widget.Init(child_params);
3311 child_widget.AddObserver(&observer);
3312 child_widget.Show();
3314 parent_widget.CloseNow();
3316 #endif // !defined(OS_CHROMEOS)
3318 // Tests that events propagate through from the dispatcher with the correct
3319 // event type, and that the different platforms behave the same.
3320 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3321 EventCountView* view = new EventCountView;
3322 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3323 view->SetBounds(10, 10, 50, 40);
3325 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3326 widget->GetRootView()->AddChildView(view);
3328 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3329 widget->Show();
3331 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3332 generator.set_current_location(gfx::Point(20, 20));
3334 generator.ClickLeftButton();
3335 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3336 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3337 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3339 generator.PressRightButton();
3340 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3341 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3342 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3344 generator.ReleaseRightButton();
3345 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3346 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3347 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3349 // Test mouse move events.
3350 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3351 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3353 // Move the mouse within the view (20, 20) -> (30, 30).
3354 generator.MoveMouseTo(gfx::Point(30, 30));
3355 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3356 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3357 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3359 // Move it again - entered count shouldn't change.
3360 generator.MoveMouseTo(gfx::Point(31, 31));
3361 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3362 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3363 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3365 // Move it off the view.
3366 generator.MoveMouseTo(gfx::Point(5, 5));
3367 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3368 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3369 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3371 // Move it back on.
3372 generator.MoveMouseTo(gfx::Point(20, 20));
3373 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3374 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3375 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3377 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3378 generator.DragMouseTo(gfx::Point(40, 40));
3379 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3380 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3381 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3382 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3384 widget->CloseNow();
3387 // Tests that the root view is correctly set up for Widget types that do not
3388 // require a non-client view, before any other views are added to the widget.
3389 // That is, before Widget::ReorderNativeViews() is called which, if called with
3390 // a root view not set, could cause the root view to get resized to the widget.
3391 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3392 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3393 View* root_view = widget->GetRootView();
3395 // Size the root view to exceed the widget bounds.
3396 const gfx::Rect test_rect(0, 0, 500, 500);
3397 root_view->SetBoundsRect(test_rect);
3399 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3401 EXPECT_EQ(test_rect, root_view->bounds());
3402 widget->ReorderNativeViews();
3403 EXPECT_EQ(test_rect, root_view->bounds());
3405 widget->CloseNow();
3408 #if defined(OS_WIN)
3409 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3410 // messages via the WindowEventTarget interface implemented by the
3411 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3412 // event
3413 TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
3414 Widget widget;
3415 Widget::InitParams params =
3416 CreateParams(Widget::InitParams::TYPE_WINDOW);
3417 params.native_widget = new PlatformDesktopNativeWidget(&widget);
3418 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3419 widget.Init(params);
3420 widget.Show();
3422 ui::WindowEventTarget* target =
3423 reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
3424 widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3425 ui::WindowEventTarget::kWin32InputEventTarget));
3426 EXPECT_NE(nullptr, target);
3427 bool handled = false;
3428 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled);
3429 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled);
3430 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled);
3431 widget.CloseNow();
3433 #endif
3435 // Test that SetAlwaysOnTop and IsAlwaysOnTop are consistent.
3436 TEST_F(WidgetTest, AlwaysOnTop) {
3437 Widget* widget = CreateTopLevelNativeWidget();
3438 EXPECT_FALSE(widget->IsAlwaysOnTop());
3439 widget->SetAlwaysOnTop(true);
3440 EXPECT_TRUE(widget->IsAlwaysOnTop());
3441 widget->SetAlwaysOnTop(false);
3442 EXPECT_FALSE(widget->IsAlwaysOnTop());
3443 widget->CloseNow();
3446 } // namespace test
3447 } // namespace views