Add ICU message format support
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blob7b72fd10f70bc58f05e180b1f9ec028359f87fbc
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 #include "ui/base/test/scoped_fake_nswindow_fullscreen.h"
45 #endif
47 namespace views {
48 namespace test {
50 namespace {
52 // TODO(tdanderson): This utility function is used in different unittest
53 // files. Move to a common location to avoid
54 // repeated code.
55 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
56 gfx::Point tmp(p);
57 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
58 return tmp;
61 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
62 bool IsTestingSnowLeopard() {
63 #if defined(OS_MACOSX)
64 return base::mac::IsOSSnowLeopard();
65 #else
66 return false;
67 #endif
70 } // namespace
72 // A view that keeps track of the events it receives, and consumes all scroll
73 // gesture events and ui::ET_SCROLL events.
74 class ScrollableEventCountView : public EventCountView {
75 public:
76 ScrollableEventCountView() {}
77 ~ScrollableEventCountView() override {}
79 private:
80 // Overridden from ui::EventHandler:
81 void OnGestureEvent(ui::GestureEvent* event) override {
82 EventCountView::OnGestureEvent(event);
83 switch (event->type()) {
84 case ui::ET_GESTURE_SCROLL_BEGIN:
85 case ui::ET_GESTURE_SCROLL_UPDATE:
86 case ui::ET_GESTURE_SCROLL_END:
87 case ui::ET_SCROLL_FLING_START:
88 event->SetHandled();
89 break;
90 default:
91 break;
95 void OnScrollEvent(ui::ScrollEvent* event) override {
96 EventCountView::OnScrollEvent(event);
97 if (event->type() == ui::ET_SCROLL)
98 event->SetHandled();
101 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
104 // A view that implements GetMinimumSize.
105 class MinimumSizeFrameView : public NativeFrameView {
106 public:
107 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
108 ~MinimumSizeFrameView() override {}
110 private:
111 // Overridden from View:
112 gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
114 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
117 // An event handler that simply keeps a count of the different types of events
118 // it receives.
119 class EventCountHandler : public ui::EventHandler {
120 public:
121 EventCountHandler() {}
122 ~EventCountHandler() override {}
124 int GetEventCount(ui::EventType type) {
125 return event_count_[type];
128 void ResetCounts() {
129 event_count_.clear();
132 protected:
133 // Overridden from ui::EventHandler:
134 void OnEvent(ui::Event* event) override {
135 RecordEvent(*event);
136 ui::EventHandler::OnEvent(event);
139 private:
140 void RecordEvent(const ui::Event& event) {
141 ++event_count_[event.type()];
144 std::map<ui::EventType, int> event_count_;
146 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
149 TEST_F(WidgetTest, WidgetInitParams) {
150 // Widgets are not transparent by default.
151 Widget::InitParams init1;
152 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
155 TEST_F(WidgetTest, NativeWindowProperty) {
156 const char* key = "foo";
157 int value = 3;
159 Widget* widget = CreateTopLevelPlatformWidget();
160 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
162 widget->SetNativeWindowProperty(key, &value);
163 EXPECT_EQ(&value, widget->GetNativeWindowProperty(key));
165 widget->SetNativeWindowProperty(key, nullptr);
166 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
168 widget->CloseNow();
171 ////////////////////////////////////////////////////////////////////////////////
172 // Widget::GetTopLevelWidget tests.
174 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
175 // Create a hierarchy of native widgets.
176 Widget* toplevel = CreateTopLevelPlatformWidget();
177 gfx::NativeView parent = toplevel->GetNativeView();
178 Widget* child = CreateChildPlatformWidget(parent);
180 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
181 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
183 toplevel->CloseNow();
184 // |child| should be automatically destroyed with |toplevel|.
187 // Test if a focus manager and an inputmethod work without CHECK failure
188 // when window activation changes.
189 TEST_F(WidgetTest, ChangeActivation) {
190 Widget* top1 = CreateTopLevelPlatformWidget();
191 top1->Show();
192 RunPendingMessages();
194 Widget* top2 = CreateTopLevelPlatformWidget();
195 top2->Show();
196 RunPendingMessages();
198 top1->Activate();
199 RunPendingMessages();
201 top2->Activate();
202 RunPendingMessages();
204 top1->Activate();
205 RunPendingMessages();
207 top1->CloseNow();
208 top2->CloseNow();
211 // Tests visibility of child widgets.
212 TEST_F(WidgetTest, Visibility) {
213 Widget* toplevel = CreateTopLevelPlatformWidget();
214 gfx::NativeView parent = toplevel->GetNativeView();
215 Widget* child = CreateChildPlatformWidget(parent);
217 EXPECT_FALSE(toplevel->IsVisible());
218 EXPECT_FALSE(child->IsVisible());
220 // Showing a child with a hidden parent keeps the child hidden.
221 child->Show();
222 EXPECT_FALSE(toplevel->IsVisible());
223 EXPECT_FALSE(child->IsVisible());
225 // Showing a hidden parent with a visible child shows both.
226 toplevel->Show();
227 EXPECT_TRUE(toplevel->IsVisible());
228 EXPECT_TRUE(child->IsVisible());
230 // Hiding a parent hides both parent and child.
231 toplevel->Hide();
232 EXPECT_FALSE(toplevel->IsVisible());
233 EXPECT_FALSE(child->IsVisible());
235 // Hiding a child while the parent is hidden keeps the child hidden when the
236 // parent is shown.
237 child->Hide();
238 toplevel->Show();
239 EXPECT_TRUE(toplevel->IsVisible());
240 EXPECT_FALSE(child->IsVisible());
242 toplevel->CloseNow();
243 // |child| should be automatically destroyed with |toplevel|.
246 // Test that child widgets are positioned relative to their parent.
247 TEST_F(WidgetTest, ChildBoundsRelativeToParent) {
248 Widget* toplevel = CreateTopLevelPlatformWidget();
249 Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
251 toplevel->SetBounds(gfx::Rect(160, 100, 320, 200));
252 child->SetBounds(gfx::Rect(0, 0, 320, 200));
254 child->Show();
255 toplevel->Show();
257 gfx::Rect toplevel_bounds = toplevel->GetWindowBoundsInScreen();
259 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
260 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds.OffsetFromOrigin());
262 // The child's origin is at (0, 0), but the same size, so bounds should match.
263 EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen());
265 toplevel->CloseNow();
268 // Test z-order of child widgets relative to their parent.
269 TEST_F(WidgetTest, ChildStackedRelativeToParent) {
270 Widget* parent = CreateTopLevelPlatformWidget();
271 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
273 parent->SetBounds(gfx::Rect(160, 100, 320, 200));
274 child->SetBounds(gfx::Rect(50, 50, 30, 20));
276 // Child shown first. Initially not visible, but on top of parent when shown.
277 // Use ShowInactive whenever showing the child, otherwise the usual activation
278 // logic will just put it on top anyway. Here, we want to ensure it is on top
279 // of its parent regardless.
280 child->ShowInactive();
281 EXPECT_FALSE(child->IsVisible());
283 parent->Show();
284 EXPECT_TRUE(child->IsVisible());
285 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
286 EXPECT_FALSE(IsWindowStackedAbove(parent, child)); // Sanity check.
288 Widget* popover = CreateTopLevelPlatformWidget();
289 popover->SetBounds(gfx::Rect(150, 90, 340, 240));
290 popover->Show();
292 EXPECT_TRUE(IsWindowStackedAbove(popover, child));
293 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
295 // Showing the parent again should raise it and its child above the popover.
296 parent->Show();
297 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
298 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
300 // Test grandchildren.
301 Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView());
302 grandchild->SetBounds(gfx::Rect(5, 5, 15, 10));
303 grandchild->ShowInactive();
304 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
305 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
306 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
308 popover->Show();
309 EXPECT_TRUE(IsWindowStackedAbove(popover, grandchild));
310 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
312 parent->Show();
313 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
314 EXPECT_TRUE(IsWindowStackedAbove(child, popover));
316 // Test hiding and reshowing.
317 parent->Hide();
318 EXPECT_FALSE(grandchild->IsVisible());
319 parent->Show();
321 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
322 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
323 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
325 grandchild->Hide();
326 EXPECT_FALSE(grandchild->IsVisible());
327 grandchild->ShowInactive();
329 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
330 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
331 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
333 popover->CloseNow();
334 parent->CloseNow();
337 ////////////////////////////////////////////////////////////////////////////////
338 // Widget ownership tests.
340 // Tests various permutations of Widget ownership specified in the
341 // InitParams::Ownership param.
343 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
344 class WidgetOwnershipTest : public WidgetTest {
345 public:
346 WidgetOwnershipTest() {}
347 ~WidgetOwnershipTest() override {}
349 void SetUp() override {
350 WidgetTest::SetUp();
351 desktop_widget_ = CreateTopLevelPlatformWidget();
354 void TearDown() override {
355 desktop_widget_->CloseNow();
356 WidgetTest::TearDown();
359 private:
360 Widget* desktop_widget_;
362 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
365 // A bag of state to monitor destructions.
366 struct OwnershipTestState {
367 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
369 bool widget_deleted;
370 bool native_widget_deleted;
373 // A platform NativeWidget subclass that updates a bag of state when it is
374 // destroyed.
375 class OwnershipTestNativeWidget : public PlatformNativeWidget {
376 public:
377 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
378 OwnershipTestState* state)
379 : PlatformNativeWidget(delegate),
380 state_(state) {
382 ~OwnershipTestNativeWidget() override {
383 state_->native_widget_deleted = true;
386 private:
387 OwnershipTestState* state_;
389 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
392 // A views NativeWidget subclass that updates a bag of state when it is
393 // destroyed.
394 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
395 public:
396 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
397 OwnershipTestState* state)
398 : NativeWidgetCapture(delegate),
399 state_(state) {
401 ~OwnershipTestNativeWidgetAura() override {
402 state_->native_widget_deleted = true;
405 private:
406 OwnershipTestState* state_;
408 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
411 // A Widget subclass that updates a bag of state when it is destroyed.
412 class OwnershipTestWidget : public Widget {
413 public:
414 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
415 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
417 private:
418 OwnershipTestState* state_;
420 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
423 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
424 // widget.
425 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
426 OwnershipTestState state;
428 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
429 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
430 params.native_widget =
431 new OwnershipTestNativeWidgetAura(widget.get(), &state);
432 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
433 widget->Init(params);
435 // Now delete the Widget, which should delete the NativeWidget.
436 widget.reset();
438 EXPECT_TRUE(state.widget_deleted);
439 EXPECT_TRUE(state.native_widget_deleted);
441 // TODO(beng): write test for this ownership scenario and the NativeWidget
442 // being deleted out from under the Widget.
445 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
446 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
447 OwnershipTestState state;
449 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
450 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
451 params.native_widget =
452 new OwnershipTestNativeWidgetAura(widget.get(), &state);
453 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
454 widget->Init(params);
456 // Now delete the Widget, which should delete the NativeWidget.
457 widget.reset();
459 EXPECT_TRUE(state.widget_deleted);
460 EXPECT_TRUE(state.native_widget_deleted);
462 // TODO(beng): write test for this ownership scenario and the NativeWidget
463 // being deleted out from under the Widget.
466 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
467 // destroy the parent view.
468 TEST_F(WidgetOwnershipTest,
469 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
470 OwnershipTestState state;
472 Widget* toplevel = CreateTopLevelPlatformWidget();
474 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
475 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
476 params.native_widget =
477 new OwnershipTestNativeWidgetAura(widget.get(), &state);
478 params.parent = toplevel->GetNativeView();
479 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
480 widget->Init(params);
482 // Now close the toplevel, which deletes the view hierarchy.
483 toplevel->CloseNow();
485 RunPendingMessages();
487 // This shouldn't delete the widget because it shouldn't be deleted
488 // from the native side.
489 EXPECT_FALSE(state.widget_deleted);
490 EXPECT_FALSE(state.native_widget_deleted);
492 // Now delete it explicitly.
493 widget.reset();
495 EXPECT_TRUE(state.widget_deleted);
496 EXPECT_TRUE(state.native_widget_deleted);
499 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
500 // widget.
501 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
502 OwnershipTestState state;
504 Widget* widget = new OwnershipTestWidget(&state);
505 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
506 params.native_widget =
507 new OwnershipTestNativeWidgetAura(widget, &state);
508 widget->Init(params);
510 // Now destroy the native widget.
511 widget->CloseNow();
513 EXPECT_TRUE(state.widget_deleted);
514 EXPECT_TRUE(state.native_widget_deleted);
517 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
518 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
519 OwnershipTestState state;
521 Widget* toplevel = CreateTopLevelPlatformWidget();
523 Widget* widget = new OwnershipTestWidget(&state);
524 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
525 params.native_widget =
526 new OwnershipTestNativeWidgetAura(widget, &state);
527 params.parent = toplevel->GetNativeView();
528 widget->Init(params);
530 // Now destroy the native widget. This is achieved by closing the toplevel.
531 toplevel->CloseNow();
533 // The NativeWidget won't be deleted until after a return to the message loop
534 // so we have to run pending messages before testing the destruction status.
535 RunPendingMessages();
537 EXPECT_TRUE(state.widget_deleted);
538 EXPECT_TRUE(state.native_widget_deleted);
541 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
542 // widget, destroyed out from under it by the OS.
543 TEST_F(WidgetOwnershipTest,
544 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
545 OwnershipTestState state;
547 Widget* widget = new OwnershipTestWidget(&state);
548 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
549 params.native_widget =
550 new OwnershipTestNativeWidgetAura(widget, &state);
551 widget->Init(params);
553 // Now simulate a destroy of the platform native widget from the OS:
554 SimulateNativeDestroy(widget);
556 EXPECT_TRUE(state.widget_deleted);
557 EXPECT_TRUE(state.native_widget_deleted);
560 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
561 // destroyed by the view hierarchy that contains it.
562 TEST_F(WidgetOwnershipTest,
563 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
564 OwnershipTestState state;
566 Widget* toplevel = CreateTopLevelPlatformWidget();
568 Widget* widget = new OwnershipTestWidget(&state);
569 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
570 params.native_widget =
571 new OwnershipTestNativeWidgetAura(widget, &state);
572 params.parent = toplevel->GetNativeView();
573 widget->Init(params);
575 // Destroy the widget (achieved by closing the toplevel).
576 toplevel->CloseNow();
578 // The NativeWidget won't be deleted until after a return to the message loop
579 // so we have to run pending messages before testing the destruction status.
580 RunPendingMessages();
582 EXPECT_TRUE(state.widget_deleted);
583 EXPECT_TRUE(state.native_widget_deleted);
586 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
587 // we close it directly.
588 TEST_F(WidgetOwnershipTest,
589 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
590 OwnershipTestState state;
592 Widget* toplevel = CreateTopLevelPlatformWidget();
594 Widget* widget = new OwnershipTestWidget(&state);
595 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
596 params.native_widget =
597 new OwnershipTestNativeWidgetAura(widget, &state);
598 params.parent = toplevel->GetNativeView();
599 widget->Init(params);
601 // Destroy the widget.
602 widget->Close();
603 toplevel->CloseNow();
605 // The NativeWidget won't be deleted until after a return to the message loop
606 // so we have to run pending messages before testing the destruction status.
607 RunPendingMessages();
609 EXPECT_TRUE(state.widget_deleted);
610 EXPECT_TRUE(state.native_widget_deleted);
613 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
614 TEST_F(WidgetOwnershipTest,
615 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
616 OwnershipTestState state;
618 WidgetDelegateView* delegate_view = new WidgetDelegateView;
620 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
621 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
622 params.native_widget =
623 new OwnershipTestNativeWidgetAura(widget.get(), &state);
624 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
625 params.delegate = delegate_view;
626 widget->Init(params);
627 widget->SetContentsView(delegate_view);
629 // Now delete the Widget. There should be no crash or use-after-free.
630 widget.reset();
632 EXPECT_TRUE(state.widget_deleted);
633 EXPECT_TRUE(state.native_widget_deleted);
636 ////////////////////////////////////////////////////////////////////////////////
637 // Test to verify using various Widget methods doesn't crash when the underlying
638 // NativeView is destroyed.
640 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
641 public:
642 WidgetWithDestroyedNativeViewTest() {}
643 ~WidgetWithDestroyedNativeViewTest() override {}
645 void InvokeWidgetMethods(Widget* widget) {
646 widget->GetNativeView();
647 widget->GetNativeWindow();
648 ui::Accelerator accelerator;
649 widget->GetAccelerator(0, &accelerator);
650 widget->GetTopLevelWidget();
651 widget->GetWindowBoundsInScreen();
652 widget->GetClientAreaBoundsInScreen();
653 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
654 widget->SetSize(gfx::Size(10, 11));
655 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
656 widget->SetVisibilityChangedAnimationsEnabled(false);
657 widget->StackAtTop();
658 widget->IsClosed();
659 widget->Close();
660 widget->Hide();
661 widget->Activate();
662 widget->Deactivate();
663 widget->IsActive();
664 widget->DisableInactiveRendering();
665 widget->SetAlwaysOnTop(true);
666 widget->IsAlwaysOnTop();
667 widget->Maximize();
668 widget->Minimize();
669 widget->Restore();
670 widget->IsMaximized();
671 widget->IsFullscreen();
672 widget->SetOpacity(0);
673 widget->SetUseDragFrame(true);
674 widget->FlashFrame(true);
675 widget->IsVisible();
676 widget->GetThemeProvider();
677 widget->GetNativeTheme();
678 widget->GetFocusManager();
679 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
680 widget->IsMouseEventsEnabled();
681 widget->SetNativeWindowProperty("xx", widget);
682 widget->GetNativeWindowProperty("xx");
683 widget->GetFocusTraversable();
684 widget->GetLayer();
685 widget->ReorderNativeViews();
686 widget->SetCapture(widget->GetRootView());
687 widget->ReleaseCapture();
688 widget->HasCapture();
689 widget->GetWorkAreaBoundsInScreen();
690 widget->IsTranslucentWindowOpacitySupported();
693 private:
694 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
697 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
699 Widget widget;
700 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
701 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
702 widget.Init(params);
703 widget.Show();
705 widget.native_widget_private()->CloseNow();
706 InvokeWidgetMethods(&widget);
708 #if !defined(OS_CHROMEOS)
710 Widget widget;
711 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
712 params.native_widget = new PlatformDesktopNativeWidget(&widget);
713 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
714 widget.Init(params);
715 widget.Show();
717 widget.native_widget_private()->CloseNow();
718 InvokeWidgetMethods(&widget);
720 #endif
723 ////////////////////////////////////////////////////////////////////////////////
724 // Widget observer tests.
727 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
728 public:
729 WidgetObserverTest()
730 : active_(nullptr),
731 widget_closed_(nullptr),
732 widget_activated_(nullptr),
733 widget_shown_(nullptr),
734 widget_hidden_(nullptr),
735 widget_bounds_changed_(nullptr),
736 widget_to_close_on_hide_(nullptr) {
739 ~WidgetObserverTest() override {}
741 // Set a widget to Close() the next time the Widget being observed is hidden.
742 void CloseOnNextHide(Widget* widget) {
743 widget_to_close_on_hide_ = widget;
746 // Overridden from WidgetObserver:
747 void OnWidgetDestroying(Widget* widget) override {
748 if (active_ == widget)
749 active_ = nullptr;
750 widget_closed_ = widget;
753 void OnWidgetActivationChanged(Widget* widget, bool active) override {
754 if (active) {
755 if (widget_activated_)
756 widget_activated_->Deactivate();
757 widget_activated_ = widget;
758 active_ = widget;
759 } else {
760 if (widget_activated_ == widget)
761 widget_activated_ = nullptr;
762 widget_deactivated_ = widget;
766 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
767 if (visible) {
768 widget_shown_ = widget;
769 return;
771 widget_hidden_ = widget;
772 if (widget_to_close_on_hide_) {
773 widget_to_close_on_hide_->Close();
774 widget_to_close_on_hide_ = nullptr;
778 void OnWidgetBoundsChanged(Widget* widget,
779 const gfx::Rect& new_bounds) override {
780 widget_bounds_changed_ = widget;
783 void reset() {
784 active_ = nullptr;
785 widget_closed_ = nullptr;
786 widget_activated_ = nullptr;
787 widget_deactivated_ = nullptr;
788 widget_shown_ = nullptr;
789 widget_hidden_ = nullptr;
790 widget_bounds_changed_ = nullptr;
793 Widget* NewWidget() {
794 Widget* widget = CreateTopLevelNativeWidget();
795 widget->AddObserver(this);
796 return widget;
799 const Widget* active() const { return active_; }
800 const Widget* widget_closed() const { return widget_closed_; }
801 const Widget* widget_activated() const { return widget_activated_; }
802 const Widget* widget_deactivated() const { return widget_deactivated_; }
803 const Widget* widget_shown() const { return widget_shown_; }
804 const Widget* widget_hidden() const { return widget_hidden_; }
805 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
807 private:
808 Widget* active_;
810 Widget* widget_closed_;
811 Widget* widget_activated_;
812 Widget* widget_deactivated_;
813 Widget* widget_shown_;
814 Widget* widget_hidden_;
815 Widget* widget_bounds_changed_;
817 Widget* widget_to_close_on_hide_;
820 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
821 Widget* toplevel = CreateTopLevelPlatformWidget();
823 Widget* toplevel1 = NewWidget();
824 Widget* toplevel2 = NewWidget();
826 toplevel1->Show();
827 toplevel2->Show();
829 reset();
831 toplevel1->Activate();
833 RunPendingMessages();
834 EXPECT_EQ(toplevel1, widget_activated());
836 toplevel2->Activate();
837 RunPendingMessages();
838 EXPECT_EQ(toplevel1, widget_deactivated());
839 EXPECT_EQ(toplevel2, widget_activated());
840 EXPECT_EQ(toplevel2, active());
842 toplevel->CloseNow();
845 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
846 Widget* toplevel = CreateTopLevelPlatformWidget();
848 Widget* child1 = NewWidget();
849 Widget* child2 = NewWidget();
851 toplevel->Show();
852 child1->Show();
853 child2->Show();
855 reset();
857 child1->Hide();
858 EXPECT_EQ(child1, widget_hidden());
860 child2->Hide();
861 EXPECT_EQ(child2, widget_hidden());
863 child1->Show();
864 EXPECT_EQ(child1, widget_shown());
866 child2->Show();
867 EXPECT_EQ(child2, widget_shown());
869 toplevel->CloseNow();
872 TEST_F(WidgetObserverTest, DestroyBubble) {
873 Widget* anchor = CreateTopLevelPlatformWidget();
874 anchor->Show();
876 BubbleDelegateView* bubble_delegate =
877 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
878 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
879 bubble_widget->Show();
880 bubble_widget->CloseNow();
882 anchor->Hide();
883 anchor->CloseNow();
886 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
887 Widget* child1 = NewWidget();
888 Widget* child2 = NewWidget();
890 child1->OnNativeWidgetMove();
891 EXPECT_EQ(child1, widget_bounds_changed());
893 child2->OnNativeWidgetMove();
894 EXPECT_EQ(child2, widget_bounds_changed());
896 child1->OnNativeWidgetSizeChanged(gfx::Size());
897 EXPECT_EQ(child1, widget_bounds_changed());
899 child2->OnNativeWidgetSizeChanged(gfx::Size());
900 EXPECT_EQ(child2, widget_bounds_changed());
902 child2->CloseNow();
903 child1->CloseNow();
906 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
907 // by the NativeWidget implementation.
908 TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
909 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
910 // consistency across platforms.
911 Widget* widget = new Widget(); // Note: owned by NativeWidget.
912 widget->AddObserver(this);
914 EXPECT_FALSE(widget_bounds_changed());
916 // Init causes a bounds change, even while not showing. Note some platforms
917 // cause a bounds change even when the bounds are empty. Mac does not.
918 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
919 params.bounds = gfx::Rect(0, 0, 100, 100);
920 widget->Init(params);
921 EXPECT_TRUE(widget_bounds_changed());
922 reset();
924 // Resizing while hidden, triggers a change.
925 widget->SetSize(gfx::Size(160, 100));
926 EXPECT_FALSE(widget->IsVisible());
927 EXPECT_TRUE(widget_bounds_changed());
928 reset();
930 // Setting the same size does nothing.
931 widget->SetSize(gfx::Size(160, 100));
932 EXPECT_FALSE(widget_bounds_changed());
933 reset();
935 // Showing does nothing to the bounds.
936 widget->Show();
937 EXPECT_TRUE(widget->IsVisible());
938 EXPECT_FALSE(widget_bounds_changed());
939 reset();
941 // Resizing while shown.
942 widget->SetSize(gfx::Size(170, 100));
943 EXPECT_TRUE(widget_bounds_changed());
944 reset();
946 // Resize to the same thing while shown does nothing.
947 widget->SetSize(gfx::Size(170, 100));
948 EXPECT_FALSE(widget_bounds_changed());
949 reset();
951 // No bounds change when closing.
952 widget->CloseNow();
953 EXPECT_FALSE(widget_bounds_changed());
956 // Test correct behavior when widgets close themselves in response to visibility
957 // changes.
958 TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
959 Widget* parent = NewWidget();
960 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
962 TestWidgetObserver child_observer(child);
964 EXPECT_FALSE(parent->IsVisible());
965 EXPECT_FALSE(child->IsVisible());
967 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
968 // child separately.
969 parent->Show();
970 EXPECT_TRUE(parent->IsVisible());
971 EXPECT_TRUE(child->IsVisible());
973 // Simulate a child widget that closes itself when the parent is hidden.
974 CloseOnNextHide(child);
975 EXPECT_FALSE(child_observer.widget_closed());
976 parent->Hide();
977 RunPendingMessages();
978 EXPECT_TRUE(child_observer.widget_closed());
980 parent->CloseNow();
983 // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
984 TEST_F(WidgetTest, GetWindowPlacement) {
985 Widget* widget;
986 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
987 // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
988 // asynchronous. Also (harder) showing a window doesn't activate it without
989 // user interaction (or extra steps only done for interactive ui tests).
990 // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
991 // TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
992 widget = CreateTopLevelPlatformWidget();
993 #else
994 widget = CreateNativeDesktopWidget();
995 #endif
997 gfx::Rect expected_bounds(100, 110, 200, 220);
998 widget->SetBounds(expected_bounds);
999 widget->Show();
1001 // Start with something invalid to ensure it changes.
1002 ui::WindowShowState show_state = ui::SHOW_STATE_END;
1003 gfx::Rect restored_bounds;
1005 internal::NativeWidgetPrivate* native_widget =
1006 widget->native_widget_private();
1008 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1009 EXPECT_EQ(expected_bounds, restored_bounds);
1010 #if defined(OS_LINUX)
1011 // Non-desktop/Ash widgets start off in "default" until a Restore().
1012 EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
1013 widget->Restore();
1014 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1015 #endif
1016 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1018 widget->Minimize();
1019 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1020 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, show_state);
1021 EXPECT_EQ(expected_bounds, restored_bounds);
1023 widget->Restore();
1024 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1025 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1026 EXPECT_EQ(expected_bounds, restored_bounds);
1028 expected_bounds = gfx::Rect(130, 140, 230, 250);
1029 widget->SetBounds(expected_bounds);
1030 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1031 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1032 EXPECT_EQ(expected_bounds, restored_bounds);
1034 widget->SetFullscreen(true);
1035 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1037 #if defined(OS_WIN)
1038 // Desktop Aura widgets on Windows currently don't update show_state when
1039 // going fullscreen, and report restored_bounds as the full screen size.
1040 // See http://crbug.com/475813.
1041 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1042 #else
1043 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, show_state);
1044 EXPECT_EQ(expected_bounds, restored_bounds);
1045 #endif
1047 widget->SetFullscreen(false);
1048 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1049 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1050 EXPECT_EQ(expected_bounds, restored_bounds);
1052 widget->CloseNow();
1055 // Test that widget size constraints are properly applied immediately after
1056 // Init(), and that SetBounds() calls are appropriately clamped.
1057 TEST_F(WidgetTest, MinimumSizeConstraints) {
1058 TestDesktopWidgetDelegate delegate;
1059 gfx::Size minimum_size(100, 100);
1060 const gfx::Size smaller_size(90, 90);
1062 delegate.set_contents_view(new StaticSizedView(minimum_size));
1063 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1064 Widget* widget = delegate.GetWidget();
1066 // On desktop Linux, the Widget must be shown to ensure the window is mapped.
1067 // On other platforms this line is optional.
1068 widget->Show();
1070 // Sanity checks.
1071 EXPECT_GT(delegate.initial_bounds().width(), minimum_size.width());
1072 EXPECT_GT(delegate.initial_bounds().height(), minimum_size.height());
1073 EXPECT_EQ(delegate.initial_bounds().size(),
1074 widget->GetWindowBoundsInScreen().size());
1075 // Note: StaticSizedView doesn't currently provide a maximum size.
1076 EXPECT_EQ(gfx::Size(), widget->GetMaximumSize());
1078 if (!widget->ShouldUseNativeFrame()) {
1079 // The test environment may have dwm disabled on Windows. In this case,
1080 // CustomFrameView is used instead of the NativeFrameView, which will
1081 // provide a minimum size that includes frame decorations.
1082 minimum_size = widget->non_client_view()->GetWindowBoundsForClientBounds(
1083 gfx::Rect(minimum_size)).size();
1086 EXPECT_EQ(minimum_size, widget->GetMinimumSize());
1087 EXPECT_EQ(minimum_size, GetNativeWidgetMinimumContentSize(widget));
1089 // Trying to resize smaller than the minimum size should restrict the content
1090 // size to the minimum size.
1091 widget->SetBounds(gfx::Rect(smaller_size));
1092 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1094 widget->SetSize(smaller_size);
1095 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1096 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it.
1097 EXPECT_EQ(smaller_size, widget->GetClientAreaBoundsInScreen().size());
1098 #else
1099 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1100 #endif
1103 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1104 // widget is visible and not maximized or fullscreen.
1105 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
1106 // Choose test coordinates away from edges and dimensions that are "small"
1107 // (but not too small) to ensure the OS doesn't try to adjust them.
1108 const gfx::Rect kTestBounds(150, 150, 400, 300);
1109 const gfx::Size kTestSize(200, 180);
1111 // First test a toplevel widget.
1112 Widget* widget = CreateTopLevelPlatformWidget();
1113 widget->Show();
1115 EXPECT_NE(kTestSize.ToString(),
1116 widget->GetWindowBoundsInScreen().size().ToString());
1117 widget->SetSize(kTestSize);
1118 EXPECT_EQ(kTestSize.ToString(),
1119 widget->GetWindowBoundsInScreen().size().ToString());
1121 EXPECT_NE(kTestBounds.ToString(),
1122 widget->GetWindowBoundsInScreen().ToString());
1123 widget->SetBounds(kTestBounds);
1124 EXPECT_EQ(kTestBounds.ToString(),
1125 widget->GetWindowBoundsInScreen().ToString());
1127 // Changing just the size should not change the origin.
1128 widget->SetSize(kTestSize);
1129 EXPECT_EQ(kTestBounds.origin().ToString(),
1130 widget->GetWindowBoundsInScreen().origin().ToString());
1132 widget->CloseNow();
1134 // Same tests with a frameless window.
1135 widget = CreateTopLevelFramelessPlatformWidget();
1136 widget->Show();
1138 EXPECT_NE(kTestSize.ToString(),
1139 widget->GetWindowBoundsInScreen().size().ToString());
1140 widget->SetSize(kTestSize);
1141 EXPECT_EQ(kTestSize.ToString(),
1142 widget->GetWindowBoundsInScreen().size().ToString());
1144 EXPECT_NE(kTestBounds.ToString(),
1145 widget->GetWindowBoundsInScreen().ToString());
1146 widget->SetBounds(kTestBounds);
1147 EXPECT_EQ(kTestBounds.ToString(),
1148 widget->GetWindowBoundsInScreen().ToString());
1150 // For a frameless widget, the client bounds should also match.
1151 EXPECT_EQ(kTestBounds.ToString(),
1152 widget->GetClientAreaBoundsInScreen().ToString());
1154 // Verify origin is stable for a frameless window as well.
1155 widget->SetSize(kTestSize);
1156 EXPECT_EQ(kTestBounds.origin().ToString(),
1157 widget->GetWindowBoundsInScreen().origin().ToString());
1159 widget->CloseNow();
1162 // Non-Desktop widgets need the shell to maximize/fullscreen window.
1163 // Disable on Linux because windows restore to the wrong bounds.
1164 // See http://crbug.com/515369.
1165 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1166 #define MAYBE_GetRestoredBounds DISABLED_GetRestoredBounds
1167 #else
1168 #define MAYBE_GetRestoredBounds GetRestoredBounds
1169 #endif
1171 // Test that GetRestoredBounds() returns the original bounds of the window.
1172 TEST_F(WidgetTest, MAYBE_GetRestoredBounds) {
1173 #if defined(OS_MACOSX)
1174 // Fullscreen on Mac requires an interactive UI test, fake them here.
1175 ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
1176 #endif
1178 Widget* toplevel = CreateNativeDesktopWidget();
1179 toplevel->Show();
1180 // Initial restored bounds have non-zero size.
1181 EXPECT_FALSE(toplevel->GetRestoredBounds().IsEmpty());
1183 const gfx::Rect bounds(100, 100, 200, 200);
1184 toplevel->SetBounds(bounds);
1185 EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
1186 EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
1188 toplevel->Maximize();
1189 RunPendingMessages();
1190 #if defined(OS_MACOSX)
1191 // Current expectation on Mac is to do nothing on Maximize.
1192 EXPECT_EQ(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
1193 #else
1194 EXPECT_NE(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
1195 #endif
1196 EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
1198 toplevel->Restore();
1199 RunPendingMessages();
1200 EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
1201 EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
1203 toplevel->SetFullscreen(true);
1204 RunPendingMessages();
1206 if (IsTestingSnowLeopard()) {
1207 // Fullscreen not implemented for Snow Leopard.
1208 EXPECT_EQ(toplevel->GetWindowBoundsInScreen(),
1209 toplevel->GetRestoredBounds());
1210 } else {
1211 EXPECT_NE(toplevel->GetWindowBoundsInScreen(),
1212 toplevel->GetRestoredBounds());
1214 EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
1216 toplevel->SetFullscreen(false);
1217 RunPendingMessages();
1218 EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
1219 EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
1221 toplevel->CloseNow();
1224 // The key-event propagation from Widget happens differently on aura and
1225 // non-aura systems because of the difference in IME. So this test works only on
1226 // aura.
1227 TEST_F(WidgetTest, KeyboardInputEvent) {
1228 Widget* toplevel = CreateTopLevelPlatformWidget();
1229 View* container = toplevel->client_view();
1231 Textfield* textfield = new Textfield();
1232 textfield->SetText(base::ASCIIToUTF16("some text"));
1233 container->AddChildView(textfield);
1234 toplevel->Show();
1235 textfield->RequestFocus();
1237 // The press gets handled. The release doesn't have an effect.
1238 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1239 toplevel->OnKeyEvent(&backspace_p);
1240 EXPECT_TRUE(backspace_p.stopped_propagation());
1241 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1242 toplevel->OnKeyEvent(&backspace_r);
1243 EXPECT_FALSE(backspace_r.handled());
1245 toplevel->Close();
1248 // Verifies bubbles result in a focus lost when shown.
1249 // TODO(msw): this tests relies on focus, it needs to be in
1250 // interactive_ui_tests.
1251 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1252 // Create a widget, show and activate it and focus the contents view.
1253 View* contents_view = new View;
1254 contents_view->SetFocusable(true);
1255 Widget widget;
1256 Widget::InitParams init_params =
1257 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1258 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1259 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1260 #if !defined(OS_CHROMEOS)
1261 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1262 #endif
1263 widget.Init(init_params);
1264 widget.SetContentsView(contents_view);
1265 widget.Show();
1266 widget.Activate();
1267 contents_view->RequestFocus();
1268 EXPECT_TRUE(contents_view->HasFocus());
1270 // Show a bubble.
1271 BubbleDelegateView* bubble_delegate_view =
1272 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1273 bubble_delegate_view->SetFocusable(true);
1274 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1275 bubble_delegate_view->RequestFocus();
1277 // |contents_view_| should no longer have focus.
1278 EXPECT_FALSE(contents_view->HasFocus());
1279 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1281 bubble_delegate_view->GetWidget()->CloseNow();
1283 // Closing the bubble should result in focus going back to the contents view.
1284 EXPECT_TRUE(contents_view->HasFocus());
1287 class TestBubbleDelegateView : public BubbleDelegateView {
1288 public:
1289 TestBubbleDelegateView(View* anchor)
1290 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1291 reset_controls_called_(false) {}
1292 ~TestBubbleDelegateView() override {}
1294 bool ShouldShowCloseButton() const override {
1295 reset_controls_called_ = true;
1296 return true;
1299 mutable bool reset_controls_called_;
1302 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1303 Widget* anchor = CreateTopLevelPlatformWidget();
1304 anchor->Show();
1306 TestBubbleDelegateView* bubble_delegate =
1307 new TestBubbleDelegateView(anchor->client_view());
1308 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1309 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1310 bubble_widget->Show();
1311 bubble_widget->CloseNow();
1313 anchor->Hide();
1314 anchor->CloseNow();
1317 #if defined(OS_WIN)
1318 // Test to ensure that after minimize, view width is set to zero. This is only
1319 // the case for desktop widgets on Windows. Other platforms retain the window
1320 // size while minimized.
1321 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1322 // Create a widget.
1323 Widget widget;
1324 Widget::InitParams init_params =
1325 CreateParams(Widget::InitParams::TYPE_WINDOW);
1326 init_params.show_state = ui::SHOW_STATE_NORMAL;
1327 gfx::Rect initial_bounds(0, 0, 300, 400);
1328 init_params.bounds = initial_bounds;
1329 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1330 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1331 widget.Init(init_params);
1332 NonClientView* non_client_view = widget.non_client_view();
1333 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1334 non_client_view->SetFrameView(frame_view);
1335 // Setting the frame view doesn't do a layout, so force one.
1336 non_client_view->Layout();
1337 widget.Show();
1338 EXPECT_NE(0, frame_view->width());
1339 widget.Minimize();
1340 EXPECT_EQ(0, frame_view->width());
1342 #endif
1344 // Desktop native widget Aura tests are for non Chrome OS platforms.
1345 #if !defined(OS_CHROMEOS)
1346 // This class validates whether paints are received for a visible Widget.
1347 // To achieve this it overrides the Show and Close methods on the Widget class
1348 // and sets state whether subsequent paints are expected.
1349 class DesktopAuraTestValidPaintWidget : public views::Widget {
1350 public:
1351 DesktopAuraTestValidPaintWidget()
1352 : received_paint_(false),
1353 expect_paint_(true),
1354 received_paint_while_hidden_(false) {}
1356 ~DesktopAuraTestValidPaintWidget() override {}
1358 void InitForTest(Widget::InitParams create_params);
1360 void Show() override {
1361 expect_paint_ = true;
1362 views::Widget::Show();
1365 void Close() override {
1366 expect_paint_ = false;
1367 views::Widget::Close();
1370 void Hide() {
1371 expect_paint_ = false;
1372 views::Widget::Hide();
1375 void OnNativeWidgetPaint(const ui::PaintContext& context) override {
1376 received_paint_ = true;
1377 EXPECT_TRUE(expect_paint_);
1378 if (!expect_paint_)
1379 received_paint_while_hidden_ = true;
1380 views::Widget::OnNativeWidgetPaint(context);
1383 bool ReadReceivedPaintAndReset() {
1384 bool result = received_paint_;
1385 received_paint_ = false;
1386 return result;
1389 bool received_paint_while_hidden() const {
1390 return received_paint_while_hidden_;
1393 private:
1394 bool received_paint_;
1395 bool expect_paint_;
1396 bool received_paint_while_hidden_;
1398 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1401 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1402 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1403 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1404 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1405 Init(init_params);
1407 View* contents_view = new View;
1408 contents_view->SetFocusable(true);
1409 SetContentsView(contents_view);
1411 Show();
1412 Activate();
1415 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1416 DesktopAuraTestValidPaintWidget widget;
1417 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1418 RunPendingMessages();
1419 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1420 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1421 widget.Close();
1422 RunPendingMessages();
1423 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1424 EXPECT_FALSE(widget.received_paint_while_hidden());
1427 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1428 DesktopAuraTestValidPaintWidget widget;
1429 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1430 RunPendingMessages();
1431 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1432 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1433 widget.Hide();
1434 RunPendingMessages();
1435 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1436 EXPECT_FALSE(widget.received_paint_while_hidden());
1437 widget.Close();
1440 // Test to ensure that the aura Window's visiblity state is set to visible if
1441 // the underlying widget is hidden and then shown.
1442 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1443 // Create a widget.
1444 Widget widget;
1445 Widget::InitParams init_params =
1446 CreateParams(Widget::InitParams::TYPE_WINDOW);
1447 init_params.show_state = ui::SHOW_STATE_NORMAL;
1448 gfx::Rect initial_bounds(0, 0, 300, 400);
1449 init_params.bounds = initial_bounds;
1450 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1451 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1452 widget.Init(init_params);
1453 NonClientView* non_client_view = widget.non_client_view();
1454 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1455 non_client_view->SetFrameView(frame_view);
1457 widget.Show();
1458 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1459 widget.Hide();
1460 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1461 widget.Show();
1462 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1465 #endif // !defined(OS_CHROMEOS)
1467 // Tests that wheel events generated from scroll events are targetted to the
1468 // views under the cursor when the focused view does not processed them.
1469 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1470 EventCountView* cursor_view = new EventCountView;
1471 cursor_view->SetBounds(60, 0, 50, 40);
1473 Widget* widget = CreateTopLevelPlatformWidget();
1474 widget->GetRootView()->AddChildView(cursor_view);
1476 // Generate a scroll event on the cursor view.
1477 ui::ScrollEvent scroll(ui::ET_SCROLL,
1478 gfx::Point(65, 5),
1479 ui::EventTimeForNow(),
1481 0, 20,
1482 0, 20,
1484 widget->OnScrollEvent(&scroll);
1486 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1487 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1489 cursor_view->ResetCounts();
1491 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1492 gfx::Point(5, 5),
1493 ui::EventTimeForNow(),
1495 0, 20,
1496 0, 20,
1498 widget->OnScrollEvent(&scroll2);
1500 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1501 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1503 widget->CloseNow();
1506 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1507 // events are not dispatched to any view.
1508 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1509 EventCountView* noscroll_view = new EventCountView;
1510 EventCountView* scroll_view = new ScrollableEventCountView;
1512 noscroll_view->SetBounds(0, 0, 50, 40);
1513 scroll_view->SetBounds(60, 0, 40, 40);
1515 Widget* widget = CreateTopLevelPlatformWidget();
1516 widget->GetRootView()->AddChildView(noscroll_view);
1517 widget->GetRootView()->AddChildView(scroll_view);
1520 ui::GestureEvent begin(
1524 base::TimeDelta(),
1525 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1526 widget->OnGestureEvent(&begin);
1527 ui::GestureEvent update(
1531 base::TimeDelta(),
1532 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1533 widget->OnGestureEvent(&update);
1534 ui::GestureEvent end(25,
1537 base::TimeDelta(),
1538 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1539 widget->OnGestureEvent(&end);
1541 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1542 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1543 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1547 ui::GestureEvent begin(
1551 base::TimeDelta(),
1552 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1553 widget->OnGestureEvent(&begin);
1554 ui::GestureEvent update(
1558 base::TimeDelta(),
1559 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1560 widget->OnGestureEvent(&update);
1561 ui::GestureEvent end(85,
1564 base::TimeDelta(),
1565 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1566 widget->OnGestureEvent(&end);
1568 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1569 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1570 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1573 widget->CloseNow();
1576 // Tests that event-handlers installed on the RootView get triggered correctly.
1577 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1578 TEST_F(WidgetTest, EventHandlersOnRootView) {
1579 Widget* widget = CreateTopLevelNativeWidget();
1580 View* root_view = widget->GetRootView();
1582 scoped_ptr<EventCountView> view(new EventCountView());
1583 view->set_owned_by_client();
1584 view->SetBounds(0, 0, 20, 20);
1585 root_view->AddChildView(view.get());
1587 EventCountHandler h1;
1588 root_view->AddPreTargetHandler(&h1);
1590 EventCountHandler h2;
1591 root_view->AddPostTargetHandler(&h2);
1593 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1594 widget->Show();
1596 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1597 // bubble up the views hierarchy to be re-dispatched on the root view.
1598 ui::ScrollEvent scroll(ui::ET_SCROLL,
1599 gfx::Point(5, 5),
1600 ui::EventTimeForNow(),
1602 0, 20,
1603 0, 20,
1605 widget->OnScrollEvent(&scroll);
1606 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1607 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1608 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1610 // Unhandled scroll events are turned into wheel events and re-dispatched.
1611 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1612 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1613 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1615 h1.ResetCounts();
1616 view->ResetCounts();
1617 h2.ResetCounts();
1619 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1620 // should bubble up the views hierarchy to be re-dispatched on the root view.
1621 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1622 gfx::Point(5, 5),
1623 ui::EventTimeForNow(),
1625 0, 20,
1626 0, 20,
1628 widget->OnScrollEvent(&fling);
1629 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1630 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1631 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1633 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1634 // be turned into wheel events and re-dispatched.
1635 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1636 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1637 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1639 h1.ResetCounts();
1640 view->ResetCounts();
1641 h2.ResetCounts();
1643 // Change the handle mode of |view| so that events are marked as handled at
1644 // the target phase.
1645 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1647 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1648 // The events are handled at the target phase and should not reach the
1649 // post-target handler.
1650 ui::GestureEvent tap_down(5,
1653 ui::EventTimeForNow(),
1654 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1655 widget->OnGestureEvent(&tap_down);
1656 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1657 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1658 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1660 ui::GestureEvent tap_cancel(
1664 ui::EventTimeForNow(),
1665 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1666 widget->OnGestureEvent(&tap_cancel);
1667 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1668 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1669 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1671 h1.ResetCounts();
1672 view->ResetCounts();
1673 h2.ResetCounts();
1675 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1676 // and should not reach the post-target handler.
1677 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1678 gfx::Point(5, 5),
1679 ui::EventTimeForNow(),
1681 0, 20,
1682 0, 20,
1684 widget->OnScrollEvent(&consumed_scroll);
1685 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1686 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1687 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1689 // Handled scroll events are not turned into wheel events and re-dispatched.
1690 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1691 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1692 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1694 widget->CloseNow();
1697 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1698 Widget* widget = CreateTopLevelNativeWidget();
1699 View* root_view = widget->GetRootView();
1701 EventCountView* v1 = new EventCountView();
1702 v1->SetBounds(0, 0, 10, 10);
1703 root_view->AddChildView(v1);
1704 EventCountView* v2 = new EventCountView();
1705 v2->SetBounds(0, 10, 10, 10);
1706 root_view->AddChildView(v2);
1708 gfx::Point cursor_location(5, 5);
1709 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1710 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
1711 widget->OnMouseEvent(&move);
1713 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1714 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1716 delete v1;
1717 v2->SetBounds(0, 0, 10, 10);
1718 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1720 widget->SynthesizeMouseMoveEvent();
1721 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1723 widget->CloseNow();
1726 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1727 #if !defined(OS_MACOSX) || defined(USE_AURA)
1729 namespace {
1731 // ui::EventHandler which handles all mouse press events.
1732 class MousePressEventConsumer : public ui::EventHandler {
1733 public:
1734 MousePressEventConsumer() {}
1736 private:
1737 // ui::EventHandler:
1738 void OnMouseEvent(ui::MouseEvent* event) override {
1739 if (event->type() == ui::ET_MOUSE_PRESSED)
1740 event->SetHandled();
1743 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1746 } // namespace
1748 // Test that mouse presses and mouse releases are dispatched normally when a
1749 // touch is down.
1750 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1751 Widget* widget = CreateTopLevelNativeWidget();
1752 widget->Show();
1753 widget->SetSize(gfx::Size(300, 300));
1755 EventCountView* event_count_view = new EventCountView();
1756 event_count_view->SetBounds(0, 0, 300, 300);
1757 widget->GetRootView()->AddChildView(event_count_view);
1759 MousePressEventConsumer consumer;
1760 event_count_view->AddPostTargetHandler(&consumer);
1762 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1763 generator.PressTouch();
1764 generator.ClickLeftButton();
1766 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1767 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1769 widget->CloseNow();
1772 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1774 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1775 // is closed.
1776 TEST_F(WidgetTest, SingleWindowClosing) {
1777 TestDesktopWidgetDelegate delegate;
1778 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1779 EXPECT_EQ(0, delegate.window_closing_count());
1780 delegate.GetWidget()->CloseNow();
1781 EXPECT_EQ(1, delegate.window_closing_count());
1784 class WidgetWindowTitleTest : public WidgetTest {
1785 protected:
1786 void RunTest(bool desktop_native_widget) {
1787 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1788 Widget::InitParams init_params =
1789 CreateParams(Widget::InitParams::TYPE_WINDOW);
1790 widget->Init(init_params);
1792 #if !defined(OS_CHROMEOS)
1793 if (desktop_native_widget)
1794 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1795 #else
1796 DCHECK(!desktop_native_widget)
1797 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1798 #endif
1800 internal::NativeWidgetPrivate* native_widget =
1801 widget->native_widget_private();
1803 base::string16 empty;
1804 base::string16 s1(base::UTF8ToUTF16("Title1"));
1805 base::string16 s2(base::UTF8ToUTF16("Title2"));
1806 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1808 // The widget starts with no title, setting empty should not change
1809 // anything.
1810 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1811 // Setting the title to something non-empty should cause a change.
1812 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1813 // Setting the title to something else with the same length should cause a
1814 // change.
1815 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1816 // Setting the title to something else with a different length should cause
1817 // a change.
1818 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1819 // Setting the title to the same thing twice should not cause a change.
1820 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1822 widget->CloseNow();
1826 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1827 // Use the default NativeWidget.
1828 bool desktop_native_widget = false;
1829 RunTest(desktop_native_widget);
1832 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1833 #if !defined(OS_CHROMEOS)
1834 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1835 // Override to use a DesktopNativeWidget.
1836 bool desktop_native_widget = true;
1837 RunTest(desktop_native_widget);
1839 #endif // !OS_CHROMEOS
1841 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1842 Widget* widget = new Widget;
1843 Widget::InitParams params =
1844 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1845 widget->Init(params);
1847 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1849 widget->SetSize(gfx::Size(100, 100));
1850 widget->Show();
1852 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1854 WidgetDeletionObserver deletion_observer(widget);
1855 generator.ClickLeftButton();
1856 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1858 // Yay we did not crash!
1861 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1862 #if !defined(OS_MACOSX) || defined(USE_AURA)
1864 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1865 Widget* widget = new Widget;
1866 Widget::InitParams params =
1867 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1868 widget->Init(params);
1870 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1872 widget->SetSize(gfx::Size(100, 100));
1873 widget->Show();
1875 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1877 WidgetDeletionObserver deletion_observer(widget);
1878 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1879 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1881 // Yay we did not crash!
1884 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1886 // See description of RunGetNativeThemeFromDestructor() for details.
1887 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1888 public:
1889 GetNativeThemeFromDestructorView() {}
1890 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1892 View* GetContentsView() override { return this; }
1894 private:
1895 void VerifyNativeTheme() {
1896 ASSERT_TRUE(GetNativeTheme() != NULL);
1899 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1902 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1903 // crash. |is_first_run| is true if this is the first call. A return value of
1904 // true indicates this should be run again with a value of false.
1905 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1906 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1907 bool is_first_run) {
1908 bool needs_second_run = false;
1909 // Destroyed by CloseNow() below.
1910 Widget* widget = new Widget;
1911 Widget::InitParams params(in_params);
1912 // Deletes itself when the Widget is destroyed.
1913 params.delegate = new GetNativeThemeFromDestructorView;
1914 #if !defined(OS_CHROMEOS)
1915 if (is_first_run) {
1916 params.native_widget = new PlatformDesktopNativeWidget(widget);
1917 needs_second_run = true;
1919 #endif
1920 widget->Init(params);
1921 widget->CloseNow();
1922 return needs_second_run;
1925 // See description of RunGetNativeThemeFromDestructor() for details.
1926 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1927 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1928 if (RunGetNativeThemeFromDestructor(params, true))
1929 RunGetNativeThemeFromDestructor(params, false);
1932 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1933 // destroyed.
1934 class CloseDestroysWidget : public Widget {
1935 public:
1936 explicit CloseDestroysWidget(bool* destroyed)
1937 : destroyed_(destroyed) {
1940 ~CloseDestroysWidget() override {
1941 if (destroyed_) {
1942 *destroyed_ = true;
1943 base::MessageLoop::current()->QuitNow();
1947 void Detach() { destroyed_ = NULL; }
1949 private:
1950 // If non-null set to true from destructor.
1951 bool* destroyed_;
1953 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1956 // An observer that registers that an animation has ended.
1957 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1958 public:
1959 AnimationEndObserver() : animation_completed_(false) {}
1960 ~AnimationEndObserver() override {}
1962 bool animation_completed() const { return animation_completed_; }
1964 // ui::ImplicitAnimationObserver:
1965 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
1967 private:
1968 bool animation_completed_;
1970 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1973 // An observer that registers the bounds of a widget on destruction.
1974 class WidgetBoundsObserver : public WidgetObserver {
1975 public:
1976 WidgetBoundsObserver() {}
1977 ~WidgetBoundsObserver() override {}
1979 gfx::Rect bounds() { return bounds_; }
1981 // WidgetObserver:
1982 void OnWidgetDestroying(Widget* widget) override {
1983 EXPECT_TRUE(widget->GetNativeWindow());
1984 bounds_ = widget->GetWindowBoundsInScreen();
1987 private:
1988 gfx::Rect bounds_;
1990 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1993 // Verifies Close() results in destroying.
1994 TEST_F(WidgetTest, CloseDestroys) {
1995 bool destroyed = false;
1996 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1997 Widget::InitParams params =
1998 CreateParams(views::Widget::InitParams::TYPE_MENU);
1999 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
2000 #if !defined(OS_CHROMEOS)
2001 params.native_widget = new PlatformDesktopNativeWidget(widget);
2002 #endif
2003 widget->Init(params);
2004 widget->Show();
2005 widget->Hide();
2006 widget->Close();
2007 EXPECT_FALSE(destroyed);
2008 // Run the message loop as Close() asynchronously deletes.
2009 base::RunLoop().Run();
2010 EXPECT_TRUE(destroyed);
2011 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2012 if (!destroyed) {
2013 widget->Detach();
2014 widget->CloseNow();
2018 // Tests that killing a widget while animating it does not crash.
2019 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
2020 scoped_ptr<Widget> widget(new Widget);
2021 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2022 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2023 params.bounds = gfx::Rect(50, 50, 250, 250);
2024 widget->Init(params);
2025 AnimationEndObserver animation_observer;
2026 WidgetBoundsObserver widget_observer;
2027 gfx::Rect bounds(0, 0, 50, 50);
2029 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2030 // animating the movement.
2031 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
2032 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2033 ui::ScopedLayerAnimationSettings animation_settings(
2034 widget->GetLayer()->GetAnimator());
2035 animation_settings.AddObserver(&animation_observer);
2036 widget->AddObserver(&widget_observer);
2037 widget->Show();
2039 // Animate the bounds change.
2040 widget->SetBounds(bounds);
2041 widget.reset();
2042 EXPECT_FALSE(animation_observer.animation_completed());
2044 EXPECT_TRUE(animation_observer.animation_completed());
2045 EXPECT_EQ(widget_observer.bounds(), bounds);
2048 // Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
2049 // and properties that depend on it are valid, when closed via CloseNow().
2050 TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
2051 Widget* widget = CreateNativeDesktopWidget();
2052 widget->Show();
2053 gfx::Rect screen_rect(50, 50, 100, 100);
2054 widget->SetBounds(screen_rect);
2055 WidgetBoundsObserver observer;
2056 widget->AddObserver(&observer);
2057 widget->CloseNow();
2058 EXPECT_EQ(screen_rect, observer.bounds());
2061 // Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
2062 // and properties that depend on it are valid, when closed via Close().
2063 TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
2064 Widget* widget = CreateNativeDesktopWidget();
2065 widget->Show();
2066 gfx::Rect screen_rect(50, 50, 100, 100);
2067 widget->SetBounds(screen_rect);
2068 WidgetBoundsObserver observer;
2069 widget->AddObserver(&observer);
2070 widget->Close();
2071 EXPECT_EQ(gfx::Rect(), observer.bounds());
2072 base::RunLoop().RunUntilIdle();
2073 // Broken on Linux. See http://crbug.com/515379.
2074 #if !defined(OS_LINUX) || defined(OS_CHROMEOS)
2075 EXPECT_EQ(screen_rect, observer.bounds());
2076 #endif
2079 // Tests that we do not crash when a Widget is destroyed by going out of
2080 // scope (as opposed to being explicitly deleted by its NativeWidget).
2081 TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
2082 scoped_ptr<Widget> widget(new Widget);
2083 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2084 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2085 widget->Init(params);
2088 // Tests that we do not crash when a Widget is destroyed before it finishes
2089 // processing of pending input events in the message loop.
2090 TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
2091 scoped_ptr<Widget> widget(new Widget);
2092 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
2093 params.bounds = gfx::Rect(0, 0, 200, 200);
2094 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2095 widget->Init(params);
2096 widget->Show();
2098 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
2099 generator.MoveMouseTo(10, 10);
2101 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2102 #if defined(OS_MACOSX) && !defined(USE_AURA)
2103 generator.ClickLeftButton();
2104 #else
2105 generator.PressTouch();
2106 #endif
2107 widget.reset();
2110 // A view that consumes mouse-pressed event and gesture-tap-down events.
2111 class RootViewTestView : public View {
2112 public:
2113 RootViewTestView(): View() {}
2115 private:
2116 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
2118 void OnGestureEvent(ui::GestureEvent* event) override {
2119 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
2120 event->SetHandled();
2124 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2125 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2126 #if defined(OS_WIN)
2127 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2128 DISABLED_TestRootViewHandlersWhenHidden
2129 #else
2130 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2131 TestRootViewHandlersWhenHidden
2132 #endif
2133 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
2134 Widget* widget = CreateTopLevelNativeWidget();
2135 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2136 View* view = new RootViewTestView();
2137 view->SetBounds(0, 0, 300, 300);
2138 internal::RootView* root_view =
2139 static_cast<internal::RootView*>(widget->GetRootView());
2140 root_view->AddChildView(view);
2142 // Check RootView::mouse_pressed_handler_.
2143 widget->Show();
2144 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2145 gfx::Point click_location(45, 15);
2146 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
2147 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2148 ui::EF_LEFT_MOUSE_BUTTON);
2149 widget->OnMouseEvent(&press);
2150 EXPECT_EQ(view, GetMousePressedHandler(root_view));
2151 widget->Hide();
2152 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2154 // Check RootView::mouse_move_handler_.
2155 widget->Show();
2156 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2157 gfx::Point move_location(45, 15);
2158 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
2159 ui::EventTimeForNow(), 0, 0);
2160 widget->OnMouseEvent(&move);
2161 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
2162 widget->Hide();
2163 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2165 // Check RootView::gesture_handler_.
2166 widget->Show();
2167 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2168 ui::GestureEvent tap_down(15,
2171 base::TimeDelta(),
2172 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2173 widget->OnGestureEvent(&tap_down);
2174 EXPECT_EQ(view, GetGestureHandler(root_view));
2175 widget->Hide();
2176 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2178 widget->Close();
2181 // Convenience to make constructing a GestureEvent simpler.
2182 class GestureEventForTest : public ui::GestureEvent {
2183 public:
2184 GestureEventForTest(ui::EventType type, int x, int y)
2185 : GestureEvent(x,
2188 base::TimeDelta(),
2189 ui::GestureEventDetails(type)) {}
2191 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2192 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2195 // Tests that the |gesture_handler_| member in RootView is always NULL
2196 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2197 // the release of the final touch point on the screen, but that
2198 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2199 // point do not modify |gesture_handler_|.
2200 TEST_F(WidgetTest, GestureEndEvents) {
2201 Widget* widget = CreateTopLevelNativeWidget();
2202 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2203 EventCountView* view = new EventCountView();
2204 view->SetBounds(0, 0, 300, 300);
2205 internal::RootView* root_view =
2206 static_cast<internal::RootView*>(widget->GetRootView());
2207 root_view->AddChildView(view);
2208 widget->Show();
2210 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2211 // the gesture handler.
2212 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2213 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2214 widget->OnGestureEvent(&end);
2215 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2217 // Change the handle mode of |view| to indicate that it would like
2218 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2219 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2220 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2221 widget->OnGestureEvent(&tap);
2222 EXPECT_TRUE(tap.handled());
2223 EXPECT_EQ(view, GetGestureHandler(root_view));
2225 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2226 // corresponding to a second touch point, but should be reset to NULL by a
2227 // ui::ET_GESTURE_END corresponding to the final touch point.
2228 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2229 details.set_touch_points(2);
2230 GestureEventForTest end_second_touch_point(details, 15, 15);
2231 widget->OnGestureEvent(&end_second_touch_point);
2232 EXPECT_EQ(view, GetGestureHandler(root_view));
2234 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2235 widget->OnGestureEvent(&end);
2236 EXPECT_TRUE(end.handled());
2237 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2239 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2240 // mode of |view| to indicate that it does not want to handle any
2241 // further events.
2242 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2243 widget->OnGestureEvent(&tap);
2244 EXPECT_TRUE(tap.handled());
2245 EXPECT_EQ(view, GetGestureHandler(root_view));
2246 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2248 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2249 // corresponding to a second touch point, but should be reset to NULL by a
2250 // ui::ET_GESTURE_END corresponding to the final touch point.
2251 end_second_touch_point = GestureEventForTest(details, 15, 15);
2252 widget->OnGestureEvent(&end_second_touch_point);
2253 EXPECT_EQ(view, GetGestureHandler(root_view));
2255 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2256 widget->OnGestureEvent(&end);
2257 EXPECT_FALSE(end.handled());
2258 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2260 widget->Close();
2263 // Tests that gesture events which should not be processed (because
2264 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2265 // dispatched to any views.
2266 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2267 Widget* widget = CreateTopLevelNativeWidget();
2268 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2270 // Define a hierarchy of four views (coordinates are in
2271 // their parent coordinate space).
2272 // v1 (0, 0, 300, 300)
2273 // v2 (0, 0, 100, 100)
2274 // v3 (0, 0, 50, 50)
2275 // v4(0, 0, 10, 10)
2276 EventCountView* v1 = new EventCountView();
2277 v1->SetBounds(0, 0, 300, 300);
2278 EventCountView* v2 = new EventCountView();
2279 v2->SetBounds(0, 0, 100, 100);
2280 EventCountView* v3 = new EventCountView();
2281 v3->SetBounds(0, 0, 50, 50);
2282 EventCountView* v4 = new EventCountView();
2283 v4->SetBounds(0, 0, 10, 10);
2284 internal::RootView* root_view =
2285 static_cast<internal::RootView*>(widget->GetRootView());
2286 root_view->AddChildView(v1);
2287 v1->AddChildView(v2);
2288 v2->AddChildView(v3);
2289 v3->AddChildView(v4);
2291 widget->Show();
2293 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2294 // they should be marked as handled by OnEventProcessingStarted().
2295 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2296 widget->OnGestureEvent(&begin);
2297 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2298 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2299 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2300 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2301 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2302 EXPECT_TRUE(begin.handled());
2303 v1->ResetCounts();
2304 v2->ResetCounts();
2305 v3->ResetCounts();
2306 v4->ResetCounts();
2308 // ui::ET_GESTURE_END events should not be seen by any view when there is
2309 // no default gesture handler set, but they should be marked as handled by
2310 // OnEventProcessingStarted().
2311 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2312 widget->OnGestureEvent(&end);
2313 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2314 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2315 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2316 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2317 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2318 EXPECT_TRUE(end.handled());
2319 v1->ResetCounts();
2320 v2->ResetCounts();
2321 v3->ResetCounts();
2322 v4->ResetCounts();
2324 // ui::ET_GESTURE_END events not corresponding to the release of the
2325 // final touch point should never be seen by any view, but they should
2326 // be marked as handled by OnEventProcessingStarted().
2327 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2328 details.set_touch_points(2);
2329 GestureEventForTest end_second_touch_point(details, 5, 5);
2330 widget->OnGestureEvent(&end_second_touch_point);
2331 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2332 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2333 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2334 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2335 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2336 EXPECT_TRUE(end_second_touch_point.handled());
2337 v1->ResetCounts();
2338 v2->ResetCounts();
2339 v3->ResetCounts();
2340 v4->ResetCounts();
2342 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2343 // there is no default gesture handler set, but they should be marked as
2344 // handled by OnEventProcessingStarted().
2345 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2346 widget->OnGestureEvent(&scroll_update);
2347 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2348 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2349 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2350 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2351 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2352 EXPECT_TRUE(scroll_update.handled());
2353 v1->ResetCounts();
2354 v2->ResetCounts();
2355 v3->ResetCounts();
2356 v4->ResetCounts();
2358 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2359 // there is no default gesture handler set, but they should be marked as
2360 // handled by OnEventProcessingStarted().
2361 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2362 widget->OnGestureEvent(&scroll_end);
2363 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2364 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2365 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2366 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2367 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2368 EXPECT_TRUE(scroll_end.handled());
2369 v1->ResetCounts();
2370 v2->ResetCounts();
2371 v3->ResetCounts();
2372 v4->ResetCounts();
2374 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2375 // there is no default gesture handler set, but they should be marked as
2376 // handled by OnEventProcessingStarted().
2377 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2378 widget->OnGestureEvent(&scroll_fling_start);
2379 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2380 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2381 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2382 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2383 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2384 EXPECT_TRUE(scroll_fling_start.handled());
2385 v1->ResetCounts();
2386 v2->ResetCounts();
2387 v3->ResetCounts();
2388 v4->ResetCounts();
2390 widget->Close();
2393 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2394 // in a view hierarchy and that the default gesture handler in RootView is set
2395 // correctly.
2396 TEST_F(WidgetTest, GestureEventDispatch) {
2397 Widget* widget = CreateTopLevelNativeWidget();
2398 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2400 // Define a hierarchy of four views (coordinates are in
2401 // their parent coordinate space).
2402 // v1 (0, 0, 300, 300)
2403 // v2 (0, 0, 100, 100)
2404 // v3 (0, 0, 50, 50)
2405 // v4(0, 0, 10, 10)
2406 EventCountView* v1 = new EventCountView();
2407 v1->SetBounds(0, 0, 300, 300);
2408 EventCountView* v2 = new EventCountView();
2409 v2->SetBounds(0, 0, 100, 100);
2410 EventCountView* v3 = new EventCountView();
2411 v3->SetBounds(0, 0, 50, 50);
2412 EventCountView* v4 = new EventCountView();
2413 v4->SetBounds(0, 0, 10, 10);
2414 internal::RootView* root_view =
2415 static_cast<internal::RootView*>(widget->GetRootView());
2416 root_view->AddChildView(v1);
2417 v1->AddChildView(v2);
2418 v2->AddChildView(v3);
2419 v3->AddChildView(v4);
2421 widget->Show();
2423 // No gesture handler is set in the root view and none of the views in the
2424 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2425 // event should be dispatched to all views in the hierarchy, the gesture
2426 // handler should remain unset, and the event should remain unhandled.
2427 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2428 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2429 widget->OnGestureEvent(&tap);
2430 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2431 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2432 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2433 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2434 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2435 EXPECT_FALSE(tap.handled());
2437 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2438 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2439 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2440 // and the event should be marked as handled.
2441 v1->ResetCounts();
2442 v2->ResetCounts();
2443 v3->ResetCounts();
2444 v4->ResetCounts();
2445 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2446 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2447 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2448 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2449 widget->OnGestureEvent(&tap);
2450 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2451 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2452 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2453 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2454 EXPECT_EQ(v3, GetGestureHandler(root_view));
2455 EXPECT_TRUE(tap.handled());
2457 // The gesture handler is set to |v3| and all views handle all gesture event
2458 // types. In this case subsequent gesture events should only be dispatched to
2459 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2460 v1->ResetCounts();
2461 v2->ResetCounts();
2462 v3->ResetCounts();
2463 v4->ResetCounts();
2464 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2465 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2466 widget->OnGestureEvent(&tap);
2467 EXPECT_TRUE(tap.handled());
2468 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2469 widget->OnGestureEvent(&show_press);
2470 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2471 widget->OnGestureEvent(&tap);
2472 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2473 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2474 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2475 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2476 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2477 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2478 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2479 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2480 EXPECT_TRUE(tap.handled());
2481 EXPECT_TRUE(show_press.handled());
2482 EXPECT_EQ(v3, GetGestureHandler(root_view));
2484 // The gesture handler is set to |v3|, but |v3| does not handle
2485 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2486 // only to |v3|, but the event should remain unhandled. The gesture handler
2487 // should remain as |v3|.
2488 v1->ResetCounts();
2489 v2->ResetCounts();
2490 v3->ResetCounts();
2491 v4->ResetCounts();
2492 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2493 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2494 widget->OnGestureEvent(&tap);
2495 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2496 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2497 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2498 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2499 EXPECT_FALSE(tap.handled());
2500 EXPECT_EQ(v3, GetGestureHandler(root_view));
2502 widget->Close();
2505 // Tests that gesture scroll events will change the default gesture handler in
2506 // RootView if the current handler to which they are dispatched does not handle
2507 // gesture scroll events.
2508 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2509 Widget* widget = CreateTopLevelNativeWidget();
2510 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2512 // Define a hierarchy of four views (coordinates are in
2513 // their parent coordinate space).
2514 // v1 (0, 0, 300, 300)
2515 // v2 (0, 0, 100, 100)
2516 // v3 (0, 0, 50, 50)
2517 // v4(0, 0, 10, 10)
2518 EventCountView* v1 = new EventCountView();
2519 v1->SetBounds(0, 0, 300, 300);
2520 EventCountView* v2 = new EventCountView();
2521 v2->SetBounds(0, 0, 100, 100);
2522 EventCountView* v3 = new EventCountView();
2523 v3->SetBounds(0, 0, 50, 50);
2524 EventCountView* v4 = new EventCountView();
2525 v4->SetBounds(0, 0, 10, 10);
2526 internal::RootView* root_view =
2527 static_cast<internal::RootView*>(widget->GetRootView());
2528 root_view->AddChildView(v1);
2529 v1->AddChildView(v2);
2530 v2->AddChildView(v3);
2531 v3->AddChildView(v4);
2533 widget->Show();
2535 // Change the handle mode of |v3| to indicate that it would like to handle
2536 // gesture events.
2537 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2539 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2540 // should bubble up the views hierarchy until it reaches the first view
2541 // that will handle it (|v3|) and then sets the handler to |v3|.
2542 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2543 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2544 widget->OnGestureEvent(&tap_down);
2545 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2546 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2547 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2548 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2549 EXPECT_EQ(v3, GetGestureHandler(root_view));
2550 EXPECT_TRUE(tap_down.handled());
2551 v1->ResetCounts();
2552 v2->ResetCounts();
2553 v3->ResetCounts();
2554 v4->ResetCounts();
2556 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2557 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2558 widget->OnGestureEvent(&tap_cancel);
2559 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2560 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2561 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2562 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2563 EXPECT_EQ(v3, GetGestureHandler(root_view));
2564 EXPECT_TRUE(tap_cancel.handled());
2565 v1->ResetCounts();
2566 v2->ResetCounts();
2567 v3->ResetCounts();
2568 v4->ResetCounts();
2570 // Change the handle mode of |v3| to indicate that it would no longer like
2571 // to handle events, and change the mode of |v1| to indicate that it would
2572 // like to handle events.
2573 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2574 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2576 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2577 // handler (|v3|) does not handle scroll events, the event should bubble up
2578 // the views hierarchy until it reaches the first view that will handle
2579 // it (|v1|) and then sets the handler to |v1|.
2580 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2581 widget->OnGestureEvent(&scroll_begin);
2582 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2583 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2584 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2585 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2586 EXPECT_EQ(v1, GetGestureHandler(root_view));
2587 EXPECT_TRUE(scroll_begin.handled());
2588 v1->ResetCounts();
2589 v2->ResetCounts();
2590 v3->ResetCounts();
2591 v4->ResetCounts();
2593 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2594 // directly.
2595 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2596 widget->OnGestureEvent(&scroll_update);
2597 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2598 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2599 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2600 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2601 EXPECT_EQ(v1, GetGestureHandler(root_view));
2602 EXPECT_TRUE(scroll_update.handled());
2603 v1->ResetCounts();
2604 v2->ResetCounts();
2605 v3->ResetCounts();
2606 v4->ResetCounts();
2608 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2609 // directly and should not reset the gesture handler.
2610 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2611 widget->OnGestureEvent(&scroll_end);
2612 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2613 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2614 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2615 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2616 EXPECT_EQ(v1, GetGestureHandler(root_view));
2617 EXPECT_TRUE(scroll_end.handled());
2618 v1->ResetCounts();
2619 v2->ResetCounts();
2620 v3->ResetCounts();
2621 v4->ResetCounts();
2623 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2624 // still be dispatched to |v1| directly.
2625 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2626 widget->OnGestureEvent(&pinch_begin);
2627 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2628 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2629 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2630 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2631 EXPECT_EQ(v1, GetGestureHandler(root_view));
2632 EXPECT_TRUE(pinch_begin.handled());
2633 v1->ResetCounts();
2634 v2->ResetCounts();
2635 v3->ResetCounts();
2636 v4->ResetCounts();
2638 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2639 // set the gesture handler to NULL.
2640 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2641 widget->OnGestureEvent(&end);
2642 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2643 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2644 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2645 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2646 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2647 EXPECT_TRUE(end.handled());
2649 widget->Close();
2652 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2653 // that when a gesture event bubbles up a View hierarchy, the location
2654 // of a gesture event seen by each View is in the local coordinate space
2655 // of that View.
2656 class GestureLocationView : public EventCountView {
2657 public:
2658 GestureLocationView() {}
2659 ~GestureLocationView() override {}
2661 void set_expected_location(gfx::Point expected_location) {
2662 expected_location_ = expected_location;
2665 // EventCountView:
2666 void OnGestureEvent(ui::GestureEvent* event) override {
2667 EventCountView::OnGestureEvent(event);
2669 // Verify that the location of |event| is in the local coordinate
2670 // space of |this|.
2671 EXPECT_EQ(expected_location_, event->location());
2674 private:
2675 // The expected location of a gesture event dispatched to |this|.
2676 gfx::Point expected_location_;
2678 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2681 // Verifies that the location of a gesture event is always in the local
2682 // coordinate space of the View receiving the event while bubbling.
2683 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2684 Widget* widget = CreateTopLevelNativeWidget();
2685 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2687 // Define a hierarchy of three views (coordinates shown below are in the
2688 // coordinate space of the root view, but the coordinates used for
2689 // SetBounds() are in their parent coordinate space).
2690 // v1 (50, 50, 150, 150)
2691 // v2 (100, 70, 50, 80)
2692 // v3 (120, 100, 10, 10)
2693 GestureLocationView* v1 = new GestureLocationView();
2694 v1->SetBounds(50, 50, 150, 150);
2695 GestureLocationView* v2 = new GestureLocationView();
2696 v2->SetBounds(50, 20, 50, 80);
2697 GestureLocationView* v3 = new GestureLocationView();
2698 v3->SetBounds(20, 30, 10, 10);
2699 internal::RootView* root_view =
2700 static_cast<internal::RootView*>(widget->GetRootView());
2701 root_view->AddChildView(v1);
2702 v1->AddChildView(v2);
2703 v2->AddChildView(v3);
2705 widget->Show();
2707 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2708 // This event is contained within all of |v1|, |v2|, and |v3|.
2709 gfx::Point location_in_root(125, 105);
2710 GestureEventForTest tap(
2711 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2713 // Calculate the location of the event in the local coordinate spaces
2714 // of each of the views.
2715 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2716 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2717 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2718 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2719 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2720 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2722 // Dispatch the event. When each view receives the event, its location should
2723 // be in the local coordinate space of that view (see the check made by
2724 // GestureLocationView). After dispatch is complete the event's location
2725 // should be in the root coordinate space.
2726 v1->set_expected_location(location_in_v1);
2727 v2->set_expected_location(location_in_v2);
2728 v3->set_expected_location(location_in_v3);
2729 widget->OnGestureEvent(&tap);
2730 EXPECT_EQ(location_in_root, tap.location());
2732 // Verify that each view did in fact see the event.
2733 EventCountView* view1 = v1;
2734 EventCountView* view2 = v2;
2735 EventCountView* view3 = v3;
2736 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2737 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2738 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2740 widget->Close();
2743 // Verifies that disabled views are permitted to be set as the default gesture
2744 // handler in RootView. Also verifies that gesture events targeted to a disabled
2745 // view are not actually dispatched to the view, but are still marked as
2746 // handled.
2747 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2748 Widget* widget = CreateTopLevelNativeWidget();
2749 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2751 // Define a hierarchy of four views (coordinates are in
2752 // their parent coordinate space).
2753 // v1 (0, 0, 300, 300)
2754 // v2 (0, 0, 100, 100)
2755 // v3 (0, 0, 50, 50)
2756 // v4(0, 0, 10, 10)
2757 EventCountView* v1 = new EventCountView();
2758 v1->SetBounds(0, 0, 300, 300);
2759 EventCountView* v2 = new EventCountView();
2760 v2->SetBounds(0, 0, 100, 100);
2761 EventCountView* v3 = new EventCountView();
2762 v3->SetBounds(0, 0, 50, 50);
2763 EventCountView* v4 = new EventCountView();
2764 v4->SetBounds(0, 0, 10, 10);
2765 internal::RootView* root_view =
2766 static_cast<internal::RootView*>(widget->GetRootView());
2767 root_view->AddChildView(v1);
2768 v1->AddChildView(v2);
2769 v2->AddChildView(v3);
2770 v3->AddChildView(v4);
2772 widget->Show();
2774 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2775 // disabled.
2776 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2777 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2778 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2779 v3->SetEnabled(false);
2781 // No gesture handler is set in the root view. In this case the tap event
2782 // should be dispatched only to |v4|, the gesture handler should be set to
2783 // |v3|, and the event should be marked as handled.
2784 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2785 widget->OnGestureEvent(&tap);
2786 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2787 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2788 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2789 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2790 EXPECT_EQ(v3, GetGestureHandler(root_view));
2791 EXPECT_TRUE(tap.handled());
2792 v1->ResetCounts();
2793 v2->ResetCounts();
2794 v3->ResetCounts();
2795 v4->ResetCounts();
2797 // A subsequent gesture event should be marked as handled but not dispatched.
2798 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2799 widget->OnGestureEvent(&tap);
2800 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2801 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2802 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2803 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2804 EXPECT_EQ(v3, GetGestureHandler(root_view));
2805 EXPECT_TRUE(tap.handled());
2806 v1->ResetCounts();
2807 v2->ResetCounts();
2808 v3->ResetCounts();
2809 v4->ResetCounts();
2811 // A GESTURE_END should reset the default gesture handler to NULL. It should
2812 // also not be dispatched to |v3| but still marked as handled.
2813 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2814 widget->OnGestureEvent(&end);
2815 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2816 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2817 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2818 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2819 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2820 EXPECT_TRUE(end.handled());
2821 v1->ResetCounts();
2822 v2->ResetCounts();
2823 v3->ResetCounts();
2824 v4->ResetCounts();
2826 // Change the handle mode of |v3| to indicate that it would no longer like
2827 // to handle events which are dispatched to it.
2828 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2830 // No gesture handler is set in the root view. In this case the tap event
2831 // should be dispatched only to |v4| and the event should be marked as
2832 // handled. Furthermore, the gesture handler should be set to
2833 // |v3|; even though |v3| does not explicitly handle events, it is a
2834 // valid target for the tap event because it is disabled.
2835 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2836 widget->OnGestureEvent(&tap);
2837 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2838 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2839 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2840 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2841 EXPECT_EQ(v3, GetGestureHandler(root_view));
2842 EXPECT_TRUE(tap.handled());
2843 v1->ResetCounts();
2844 v2->ResetCounts();
2845 v3->ResetCounts();
2846 v4->ResetCounts();
2848 // A GESTURE_END should reset the default gesture handler to NULL. It should
2849 // also not be dispatched to |v3| but still marked as handled.
2850 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2851 widget->OnGestureEvent(&end);
2852 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2853 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2854 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2855 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2856 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2857 EXPECT_TRUE(end.handled());
2859 widget->Close();
2862 // Test the result of Widget::GetAllChildWidgets().
2863 TEST_F(WidgetTest, GetAllChildWidgets) {
2864 // Create the following widget hierarchy:
2866 // toplevel
2867 // +-- w1
2868 // +-- w11
2869 // +-- w2
2870 // +-- w21
2871 // +-- w22
2872 Widget* toplevel = CreateTopLevelPlatformWidget();
2873 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2874 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2875 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2876 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2877 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2879 std::set<Widget*> expected;
2880 expected.insert(toplevel);
2881 expected.insert(w1);
2882 expected.insert(w11);
2883 expected.insert(w2);
2884 expected.insert(w21);
2885 expected.insert(w22);
2887 std::set<Widget*> widgets;
2888 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2890 EXPECT_EQ(expected.size(), widgets.size());
2891 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2892 toplevel->CloseNow();
2895 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2896 // a vector.
2897 class DestroyedTrackingView : public View {
2898 public:
2899 DestroyedTrackingView(const std::string& name,
2900 std::vector<std::string>* add_to)
2901 : name_(name),
2902 add_to_(add_to) {
2905 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2907 private:
2908 const std::string name_;
2909 std::vector<std::string>* add_to_;
2911 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2914 class WidgetChildDestructionTest : public WidgetTest {
2915 public:
2916 WidgetChildDestructionTest() {}
2918 // Creates a top level and a child, destroys the child and verifies the views
2919 // of the child are destroyed before the views of the parent.
2920 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2921 bool child_has_desktop_native_widget_aura) {
2922 // When a View is destroyed its name is added here.
2923 std::vector<std::string> destroyed;
2925 Widget* top_level = new Widget;
2926 Widget::InitParams params =
2927 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2928 #if !defined(OS_CHROMEOS)
2929 if (top_level_has_desktop_native_widget_aura)
2930 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2931 #endif
2932 top_level->Init(params);
2933 top_level->GetRootView()->AddChildView(
2934 new DestroyedTrackingView("parent", &destroyed));
2935 top_level->Show();
2937 Widget* child = new Widget;
2938 Widget::InitParams child_params =
2939 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2940 child_params.parent = top_level->GetNativeView();
2941 #if !defined(OS_CHROMEOS)
2942 if (child_has_desktop_native_widget_aura)
2943 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2944 #endif
2945 child->Init(child_params);
2946 child->GetRootView()->AddChildView(
2947 new DestroyedTrackingView("child", &destroyed));
2948 child->Show();
2950 // Should trigger destruction of the child too.
2951 top_level->native_widget_private()->CloseNow();
2953 // Child should be destroyed first.
2954 ASSERT_EQ(2u, destroyed.size());
2955 EXPECT_EQ("child", destroyed[0]);
2956 EXPECT_EQ("parent", destroyed[1]);
2959 private:
2960 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2963 #if !defined(OS_CHROMEOS)
2964 // See description of RunDestroyChildWidgetsTest(). Parent uses
2965 // DesktopNativeWidgetAura.
2966 TEST_F(WidgetChildDestructionTest,
2967 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2968 RunDestroyChildWidgetsTest(true, false);
2971 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2972 // DesktopNativeWidgetAura.
2973 TEST_F(WidgetChildDestructionTest,
2974 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2975 RunDestroyChildWidgetsTest(true, true);
2977 #endif // !defined(OS_CHROMEOS)
2979 // See description of RunDestroyChildWidgetsTest().
2980 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2981 RunDestroyChildWidgetsTest(false, false);
2984 // Verifies nativeview visbility matches that of Widget visibility when
2985 // SetFullscreen is invoked.
2986 TEST_F(WidgetTest, FullscreenStatePropagated) {
2987 Widget::InitParams init_params =
2988 CreateParams(Widget::InitParams::TYPE_WINDOW);
2989 init_params.show_state = ui::SHOW_STATE_NORMAL;
2990 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2991 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2994 Widget top_level_widget;
2995 top_level_widget.Init(init_params);
2996 top_level_widget.SetFullscreen(true);
2997 EXPECT_EQ(top_level_widget.IsVisible(),
2998 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2999 top_level_widget.CloseNow();
3001 #if !defined(OS_CHROMEOS)
3003 Widget top_level_widget;
3004 init_params.native_widget =
3005 new PlatformDesktopNativeWidget(&top_level_widget);
3006 top_level_widget.Init(init_params);
3007 top_level_widget.SetFullscreen(true);
3008 EXPECT_EQ(top_level_widget.IsVisible(),
3009 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3010 top_level_widget.CloseNow();
3012 #endif
3015 namespace {
3017 class FullscreenAwareFrame : public views::NonClientFrameView {
3018 public:
3019 explicit FullscreenAwareFrame(views::Widget* widget)
3020 : widget_(widget), fullscreen_layout_called_(false) {}
3021 ~FullscreenAwareFrame() override {}
3023 // views::NonClientFrameView overrides:
3024 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3025 gfx::Rect GetWindowBoundsForClientBounds(
3026 const gfx::Rect& client_bounds) const override {
3027 return gfx::Rect();
3029 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3030 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3031 void ResetWindowControls() override {}
3032 void UpdateWindowIcon() override {}
3033 void UpdateWindowTitle() override {}
3034 void SizeConstraintsChanged() override {}
3036 // views::View overrides:
3037 void Layout() override {
3038 if (widget_->IsFullscreen())
3039 fullscreen_layout_called_ = true;
3042 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3044 private:
3045 views::Widget* widget_;
3046 bool fullscreen_layout_called_;
3048 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3051 } // namespace
3053 // Tests that frame Layout is called when a widget goes fullscreen without
3054 // changing its size or title.
3055 TEST_F(WidgetTest, FullscreenFrameLayout) {
3056 Widget* widget = CreateTopLevelPlatformWidget();
3057 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3058 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3060 widget->Maximize();
3061 RunPendingMessages();
3063 EXPECT_FALSE(frame->fullscreen_layout_called());
3064 widget->SetFullscreen(true);
3065 widget->Show();
3066 RunPendingMessages();
3068 if (IsTestingSnowLeopard()) {
3069 // Fullscreen is currently ignored on Snow Leopard.
3070 EXPECT_FALSE(frame->fullscreen_layout_called());
3071 } else {
3072 EXPECT_TRUE(frame->fullscreen_layout_called());
3075 widget->CloseNow();
3078 #if !defined(OS_CHROMEOS)
3079 namespace {
3081 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3082 // OnWindowDestroying.
3083 class IsActiveFromDestroyObserver : public WidgetObserver {
3084 public:
3085 IsActiveFromDestroyObserver() {}
3086 ~IsActiveFromDestroyObserver() override {}
3087 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3089 private:
3090 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3093 } // namespace
3095 // Verifies Widget::IsActive() invoked from
3096 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3097 TEST_F(WidgetTest, IsActiveFromDestroy) {
3098 // Create two widgets, one a child of the other.
3099 IsActiveFromDestroyObserver observer;
3100 Widget parent_widget;
3101 Widget::InitParams parent_params =
3102 CreateParams(Widget::InitParams::TYPE_POPUP);
3103 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3104 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3105 parent_widget.Init(parent_params);
3106 parent_widget.Show();
3108 Widget child_widget;
3109 Widget::InitParams child_params =
3110 CreateParams(Widget::InitParams::TYPE_POPUP);
3111 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3112 child_params.context = parent_widget.GetNativeWindow();
3113 child_widget.Init(child_params);
3114 child_widget.AddObserver(&observer);
3115 child_widget.Show();
3117 parent_widget.CloseNow();
3119 #endif // !defined(OS_CHROMEOS)
3121 // Tests that events propagate through from the dispatcher with the correct
3122 // event type, and that the different platforms behave the same.
3123 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3124 EventCountView* view = new EventCountView;
3125 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3126 view->SetBounds(10, 10, 50, 40);
3128 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3129 widget->GetRootView()->AddChildView(view);
3131 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3132 widget->Show();
3134 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3135 generator.set_current_location(gfx::Point(20, 20));
3137 generator.ClickLeftButton();
3138 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3139 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3140 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3142 generator.PressRightButton();
3143 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3144 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3145 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3147 generator.ReleaseRightButton();
3148 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3149 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3150 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3152 // Test mouse move events.
3153 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3154 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3156 // Move the mouse within the view (20, 20) -> (30, 30).
3157 generator.MoveMouseTo(gfx::Point(30, 30));
3158 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3159 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3160 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3162 // Move it again - entered count shouldn't change.
3163 generator.MoveMouseTo(gfx::Point(31, 31));
3164 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3165 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3166 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3168 // Move it off the view.
3169 generator.MoveMouseTo(gfx::Point(5, 5));
3170 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3171 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3172 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3174 // Move it back on.
3175 generator.MoveMouseTo(gfx::Point(20, 20));
3176 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3177 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3178 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3180 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3181 generator.DragMouseTo(gfx::Point(40, 40));
3182 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3183 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3184 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3185 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3187 widget->CloseNow();
3190 // Tests that the root view is correctly set up for Widget types that do not
3191 // require a non-client view, before any other views are added to the widget.
3192 // That is, before Widget::ReorderNativeViews() is called which, if called with
3193 // a root view not set, could cause the root view to get resized to the widget.
3194 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3195 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3196 View* root_view = widget->GetRootView();
3198 // Size the root view to exceed the widget bounds.
3199 const gfx::Rect test_rect(0, 0, 500, 500);
3200 root_view->SetBoundsRect(test_rect);
3202 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3204 EXPECT_EQ(test_rect, root_view->bounds());
3205 widget->ReorderNativeViews();
3206 EXPECT_EQ(test_rect, root_view->bounds());
3208 widget->CloseNow();
3211 #if defined(OS_WIN)
3212 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3213 // messages via the WindowEventTarget interface implemented by the
3214 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3215 // event
3216 TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
3217 Widget widget;
3218 Widget::InitParams params =
3219 CreateParams(Widget::InitParams::TYPE_WINDOW);
3220 params.native_widget = new PlatformDesktopNativeWidget(&widget);
3221 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3222 widget.Init(params);
3223 widget.Show();
3225 ui::WindowEventTarget* target =
3226 reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
3227 widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3228 ui::WindowEventTarget::kWin32InputEventTarget));
3229 EXPECT_NE(nullptr, target);
3230 bool handled = false;
3231 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled);
3232 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled);
3233 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled);
3234 widget.CloseNow();
3236 #endif
3238 // Test that SetAlwaysOnTop and IsAlwaysOnTop are consistent.
3239 TEST_F(WidgetTest, AlwaysOnTop) {
3240 Widget* widget = CreateTopLevelNativeWidget();
3241 EXPECT_FALSE(widget->IsAlwaysOnTop());
3242 widget->SetAlwaysOnTop(true);
3243 EXPECT_TRUE(widget->IsAlwaysOnTop());
3244 widget->SetAlwaysOnTop(false);
3245 EXPECT_FALSE(widget->IsAlwaysOnTop());
3246 widget->CloseNow();
3249 } // namespace test
3250 } // namespace views