Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobb6a18a94f675921c4f4f6c2607aa01ddf69fdb27
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();
1700 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1702 EventCountView* v1 = new EventCountView();
1703 v1->SetBounds(5, 5, 10, 10);
1704 root_view->AddChildView(v1);
1705 EventCountView* v2 = new EventCountView();
1706 v2->SetBounds(5, 15, 10, 10);
1707 root_view->AddChildView(v2);
1709 widget->Show();
1711 // SynthesizeMouseMoveEvent does nothing until the mouse is entered.
1712 widget->SynthesizeMouseMoveEvent();
1713 EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_MOVED));
1714 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
1716 gfx::Point cursor_location(5, 5);
1717 View::ConvertPointToScreen(widget->GetRootView(), &cursor_location);
1718 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1719 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
1720 ui::EventDispatchDetails details =
1721 WidgetTest::GetEventProcessor(widget)->OnEventFromSource(&move);
1722 EXPECT_FALSE(details.dispatcher_destroyed);
1724 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_MOVED));
1725 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
1727 // SynthesizeMouseMoveEvent dispatches an mousemove event.
1728 widget->SynthesizeMouseMoveEvent();
1729 EXPECT_EQ(2, v1->GetEventCount(ui::ET_MOUSE_MOVED));
1731 delete v1;
1732 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
1733 v2->SetBounds(5, 5, 10, 10);
1734 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
1736 widget->SynthesizeMouseMoveEvent();
1737 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_MOVED));
1739 widget->CloseNow();
1742 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1743 #if !defined(OS_MACOSX) || defined(USE_AURA)
1745 namespace {
1747 // ui::EventHandler which handles all mouse press events.
1748 class MousePressEventConsumer : public ui::EventHandler {
1749 public:
1750 MousePressEventConsumer() {}
1752 private:
1753 // ui::EventHandler:
1754 void OnMouseEvent(ui::MouseEvent* event) override {
1755 if (event->type() == ui::ET_MOUSE_PRESSED)
1756 event->SetHandled();
1759 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1762 } // namespace
1764 // Test that mouse presses and mouse releases are dispatched normally when a
1765 // touch is down.
1766 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1767 Widget* widget = CreateTopLevelNativeWidget();
1768 widget->Show();
1769 widget->SetSize(gfx::Size(300, 300));
1771 EventCountView* event_count_view = new EventCountView();
1772 event_count_view->SetBounds(0, 0, 300, 300);
1773 widget->GetRootView()->AddChildView(event_count_view);
1775 MousePressEventConsumer consumer;
1776 event_count_view->AddPostTargetHandler(&consumer);
1778 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1779 generator.PressTouch();
1780 generator.ClickLeftButton();
1782 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1783 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1785 widget->CloseNow();
1788 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1790 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1791 // is closed.
1792 TEST_F(WidgetTest, SingleWindowClosing) {
1793 TestDesktopWidgetDelegate delegate;
1794 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1795 EXPECT_EQ(0, delegate.window_closing_count());
1796 delegate.GetWidget()->CloseNow();
1797 EXPECT_EQ(1, delegate.window_closing_count());
1800 class WidgetWindowTitleTest : public WidgetTest {
1801 protected:
1802 void RunTest(bool desktop_native_widget) {
1803 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1804 Widget::InitParams init_params =
1805 CreateParams(Widget::InitParams::TYPE_WINDOW);
1806 widget->Init(init_params);
1808 #if !defined(OS_CHROMEOS)
1809 if (desktop_native_widget)
1810 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1811 #else
1812 DCHECK(!desktop_native_widget)
1813 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1814 #endif
1816 internal::NativeWidgetPrivate* native_widget =
1817 widget->native_widget_private();
1819 base::string16 empty;
1820 base::string16 s1(base::UTF8ToUTF16("Title1"));
1821 base::string16 s2(base::UTF8ToUTF16("Title2"));
1822 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1824 // The widget starts with no title, setting empty should not change
1825 // anything.
1826 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1827 // Setting the title to something non-empty should cause a change.
1828 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1829 // Setting the title to something else with the same length should cause a
1830 // change.
1831 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1832 // Setting the title to something else with a different length should cause
1833 // a change.
1834 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1835 // Setting the title to the same thing twice should not cause a change.
1836 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1838 widget->CloseNow();
1842 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1843 // Use the default NativeWidget.
1844 bool desktop_native_widget = false;
1845 RunTest(desktop_native_widget);
1848 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1849 #if !defined(OS_CHROMEOS)
1850 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1851 // Override to use a DesktopNativeWidget.
1852 bool desktop_native_widget = true;
1853 RunTest(desktop_native_widget);
1855 #endif // !OS_CHROMEOS
1857 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1858 Widget* widget = new Widget;
1859 Widget::InitParams params =
1860 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1861 widget->Init(params);
1863 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1865 widget->SetSize(gfx::Size(100, 100));
1866 widget->Show();
1868 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1870 WidgetDeletionObserver deletion_observer(widget);
1871 generator.ClickLeftButton();
1872 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1874 // Yay we did not crash!
1877 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1878 #if !defined(OS_MACOSX) || defined(USE_AURA)
1880 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1881 Widget* widget = new Widget;
1882 Widget::InitParams params =
1883 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1884 widget->Init(params);
1886 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1888 widget->SetSize(gfx::Size(100, 100));
1889 widget->Show();
1891 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1893 WidgetDeletionObserver deletion_observer(widget);
1894 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1895 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1897 // Yay we did not crash!
1900 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1902 // See description of RunGetNativeThemeFromDestructor() for details.
1903 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1904 public:
1905 GetNativeThemeFromDestructorView() {}
1906 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1908 View* GetContentsView() override { return this; }
1910 private:
1911 void VerifyNativeTheme() {
1912 ASSERT_TRUE(GetNativeTheme() != NULL);
1915 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1918 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1919 // crash. |is_first_run| is true if this is the first call. A return value of
1920 // true indicates this should be run again with a value of false.
1921 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1922 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1923 bool is_first_run) {
1924 bool needs_second_run = false;
1925 // Destroyed by CloseNow() below.
1926 Widget* widget = new Widget;
1927 Widget::InitParams params(in_params);
1928 // Deletes itself when the Widget is destroyed.
1929 params.delegate = new GetNativeThemeFromDestructorView;
1930 #if !defined(OS_CHROMEOS)
1931 if (is_first_run) {
1932 params.native_widget = new PlatformDesktopNativeWidget(widget);
1933 needs_second_run = true;
1935 #endif
1936 widget->Init(params);
1937 widget->CloseNow();
1938 return needs_second_run;
1941 // See description of RunGetNativeThemeFromDestructor() for details.
1942 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1943 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1944 if (RunGetNativeThemeFromDestructor(params, true))
1945 RunGetNativeThemeFromDestructor(params, false);
1948 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1949 // destroyed.
1950 class CloseDestroysWidget : public Widget {
1951 public:
1952 explicit CloseDestroysWidget(bool* destroyed)
1953 : destroyed_(destroyed) {
1956 ~CloseDestroysWidget() override {
1957 if (destroyed_) {
1958 *destroyed_ = true;
1959 base::MessageLoop::current()->QuitNow();
1963 void Detach() { destroyed_ = NULL; }
1965 private:
1966 // If non-null set to true from destructor.
1967 bool* destroyed_;
1969 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1972 // An observer that registers that an animation has ended.
1973 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1974 public:
1975 AnimationEndObserver() : animation_completed_(false) {}
1976 ~AnimationEndObserver() override {}
1978 bool animation_completed() const { return animation_completed_; }
1980 // ui::ImplicitAnimationObserver:
1981 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
1983 private:
1984 bool animation_completed_;
1986 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1989 // An observer that registers the bounds of a widget on destruction.
1990 class WidgetBoundsObserver : public WidgetObserver {
1991 public:
1992 WidgetBoundsObserver() {}
1993 ~WidgetBoundsObserver() override {}
1995 gfx::Rect bounds() { return bounds_; }
1997 // WidgetObserver:
1998 void OnWidgetDestroying(Widget* widget) override {
1999 EXPECT_TRUE(widget->GetNativeWindow());
2000 bounds_ = widget->GetWindowBoundsInScreen();
2003 private:
2004 gfx::Rect bounds_;
2006 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
2009 // Verifies Close() results in destroying.
2010 TEST_F(WidgetTest, CloseDestroys) {
2011 bool destroyed = false;
2012 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
2013 Widget::InitParams params =
2014 CreateParams(views::Widget::InitParams::TYPE_MENU);
2015 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
2016 #if !defined(OS_CHROMEOS)
2017 params.native_widget = new PlatformDesktopNativeWidget(widget);
2018 #endif
2019 widget->Init(params);
2020 widget->Show();
2021 widget->Hide();
2022 widget->Close();
2023 EXPECT_FALSE(destroyed);
2024 // Run the message loop as Close() asynchronously deletes.
2025 base::RunLoop().Run();
2026 EXPECT_TRUE(destroyed);
2027 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2028 if (!destroyed) {
2029 widget->Detach();
2030 widget->CloseNow();
2034 // Tests that killing a widget while animating it does not crash.
2035 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
2036 scoped_ptr<Widget> widget(new Widget);
2037 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2038 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2039 params.bounds = gfx::Rect(50, 50, 250, 250);
2040 widget->Init(params);
2041 AnimationEndObserver animation_observer;
2042 WidgetBoundsObserver widget_observer;
2043 gfx::Rect bounds(100, 100, 50, 50);
2045 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2046 // animating the movement.
2047 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
2048 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2049 ui::ScopedLayerAnimationSettings animation_settings(
2050 widget->GetLayer()->GetAnimator());
2051 animation_settings.AddObserver(&animation_observer);
2052 widget->AddObserver(&widget_observer);
2053 widget->Show();
2055 // Animate the bounds change.
2056 widget->SetBounds(bounds);
2057 widget.reset();
2058 EXPECT_FALSE(animation_observer.animation_completed());
2060 EXPECT_TRUE(animation_observer.animation_completed());
2061 EXPECT_EQ(widget_observer.bounds(), bounds);
2064 // Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
2065 // and properties that depend on it are valid, when closed via CloseNow().
2066 TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
2067 Widget* widget = CreateNativeDesktopWidget();
2068 widget->Show();
2069 gfx::Rect screen_rect(50, 50, 100, 100);
2070 widget->SetBounds(screen_rect);
2071 WidgetBoundsObserver observer;
2072 widget->AddObserver(&observer);
2073 widget->CloseNow();
2074 EXPECT_EQ(screen_rect, observer.bounds());
2077 // Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
2078 // and properties that depend on it are valid, when closed via Close().
2079 TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
2080 Widget* widget = CreateNativeDesktopWidget();
2081 widget->Show();
2082 gfx::Rect screen_rect(50, 50, 100, 100);
2083 widget->SetBounds(screen_rect);
2084 WidgetBoundsObserver observer;
2085 widget->AddObserver(&observer);
2086 widget->Close();
2087 EXPECT_EQ(gfx::Rect(), observer.bounds());
2088 base::RunLoop().RunUntilIdle();
2089 // Broken on Linux. See http://crbug.com/515379.
2090 #if !defined(OS_LINUX) || defined(OS_CHROMEOS)
2091 EXPECT_EQ(screen_rect, observer.bounds());
2092 #endif
2095 // Tests that we do not crash when a Widget is destroyed by going out of
2096 // scope (as opposed to being explicitly deleted by its NativeWidget).
2097 TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
2098 scoped_ptr<Widget> widget(new Widget);
2099 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2100 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2101 widget->Init(params);
2104 // Tests that we do not crash when a Widget is destroyed before it finishes
2105 // processing of pending input events in the message loop.
2106 TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
2107 scoped_ptr<Widget> widget(new Widget);
2108 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
2109 params.bounds = gfx::Rect(0, 0, 200, 200);
2110 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2111 widget->Init(params);
2112 widget->Show();
2114 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
2115 generator.MoveMouseTo(10, 10);
2117 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2118 #if defined(OS_MACOSX) && !defined(USE_AURA)
2119 generator.ClickLeftButton();
2120 #else
2121 generator.PressTouch();
2122 #endif
2123 widget.reset();
2126 // A view that consumes mouse-pressed event and gesture-tap-down events.
2127 class RootViewTestView : public View {
2128 public:
2129 RootViewTestView(): View() {}
2131 private:
2132 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
2134 void OnGestureEvent(ui::GestureEvent* event) override {
2135 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
2136 event->SetHandled();
2140 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2141 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2142 #if defined(OS_WIN)
2143 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2144 DISABLED_TestRootViewHandlersWhenHidden
2145 #else
2146 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2147 TestRootViewHandlersWhenHidden
2148 #endif
2149 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
2150 Widget* widget = CreateTopLevelNativeWidget();
2151 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2152 View* view = new RootViewTestView();
2153 view->SetBounds(0, 0, 300, 300);
2154 internal::RootView* root_view =
2155 static_cast<internal::RootView*>(widget->GetRootView());
2156 root_view->AddChildView(view);
2158 // Check RootView::mouse_pressed_handler_.
2159 widget->Show();
2160 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2161 gfx::Point click_location(45, 15);
2162 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
2163 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2164 ui::EF_LEFT_MOUSE_BUTTON);
2165 widget->OnMouseEvent(&press);
2166 EXPECT_EQ(view, GetMousePressedHandler(root_view));
2167 widget->Hide();
2168 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2170 // Check RootView::mouse_move_handler_.
2171 widget->Show();
2172 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2173 gfx::Point move_location(45, 15);
2174 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
2175 ui::EventTimeForNow(), 0, 0);
2176 widget->OnMouseEvent(&move);
2177 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
2178 widget->Hide();
2179 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2181 // Check RootView::gesture_handler_.
2182 widget->Show();
2183 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2184 ui::GestureEvent tap_down(15,
2187 base::TimeDelta(),
2188 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2189 widget->OnGestureEvent(&tap_down);
2190 EXPECT_EQ(view, GetGestureHandler(root_view));
2191 widget->Hide();
2192 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2194 widget->Close();
2197 // Convenience to make constructing a GestureEvent simpler.
2198 class GestureEventForTest : public ui::GestureEvent {
2199 public:
2200 GestureEventForTest(ui::EventType type, int x, int y)
2201 : GestureEvent(x,
2204 base::TimeDelta(),
2205 ui::GestureEventDetails(type)) {}
2207 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2208 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2211 // Tests that the |gesture_handler_| member in RootView is always NULL
2212 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2213 // the release of the final touch point on the screen, but that
2214 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2215 // point do not modify |gesture_handler_|.
2216 TEST_F(WidgetTest, GestureEndEvents) {
2217 Widget* widget = CreateTopLevelNativeWidget();
2218 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2219 EventCountView* view = new EventCountView();
2220 view->SetBounds(0, 0, 300, 300);
2221 internal::RootView* root_view =
2222 static_cast<internal::RootView*>(widget->GetRootView());
2223 root_view->AddChildView(view);
2224 widget->Show();
2226 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2227 // the gesture handler.
2228 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2229 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2230 widget->OnGestureEvent(&end);
2231 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2233 // Change the handle mode of |view| to indicate that it would like
2234 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2235 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2236 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2237 widget->OnGestureEvent(&tap);
2238 EXPECT_TRUE(tap.handled());
2239 EXPECT_EQ(view, GetGestureHandler(root_view));
2241 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2242 // corresponding to a second touch point, but should be reset to NULL by a
2243 // ui::ET_GESTURE_END corresponding to the final touch point.
2244 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2245 details.set_touch_points(2);
2246 GestureEventForTest end_second_touch_point(details, 15, 15);
2247 widget->OnGestureEvent(&end_second_touch_point);
2248 EXPECT_EQ(view, GetGestureHandler(root_view));
2250 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2251 widget->OnGestureEvent(&end);
2252 EXPECT_TRUE(end.handled());
2253 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2255 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2256 // mode of |view| to indicate that it does not want to handle any
2257 // further events.
2258 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2259 widget->OnGestureEvent(&tap);
2260 EXPECT_TRUE(tap.handled());
2261 EXPECT_EQ(view, GetGestureHandler(root_view));
2262 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2264 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2265 // corresponding to a second touch point, but should be reset to NULL by a
2266 // ui::ET_GESTURE_END corresponding to the final touch point.
2267 end_second_touch_point = GestureEventForTest(details, 15, 15);
2268 widget->OnGestureEvent(&end_second_touch_point);
2269 EXPECT_EQ(view, GetGestureHandler(root_view));
2271 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2272 widget->OnGestureEvent(&end);
2273 EXPECT_FALSE(end.handled());
2274 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2276 widget->Close();
2279 // Tests that gesture events which should not be processed (because
2280 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2281 // dispatched to any views.
2282 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2283 Widget* widget = CreateTopLevelNativeWidget();
2284 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2286 // Define a hierarchy of four views (coordinates are in
2287 // their parent coordinate space).
2288 // v1 (0, 0, 300, 300)
2289 // v2 (0, 0, 100, 100)
2290 // v3 (0, 0, 50, 50)
2291 // v4(0, 0, 10, 10)
2292 EventCountView* v1 = new EventCountView();
2293 v1->SetBounds(0, 0, 300, 300);
2294 EventCountView* v2 = new EventCountView();
2295 v2->SetBounds(0, 0, 100, 100);
2296 EventCountView* v3 = new EventCountView();
2297 v3->SetBounds(0, 0, 50, 50);
2298 EventCountView* v4 = new EventCountView();
2299 v4->SetBounds(0, 0, 10, 10);
2300 internal::RootView* root_view =
2301 static_cast<internal::RootView*>(widget->GetRootView());
2302 root_view->AddChildView(v1);
2303 v1->AddChildView(v2);
2304 v2->AddChildView(v3);
2305 v3->AddChildView(v4);
2307 widget->Show();
2309 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2310 // they should be marked as handled by OnEventProcessingStarted().
2311 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2312 widget->OnGestureEvent(&begin);
2313 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2314 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2315 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2316 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2317 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2318 EXPECT_TRUE(begin.handled());
2319 v1->ResetCounts();
2320 v2->ResetCounts();
2321 v3->ResetCounts();
2322 v4->ResetCounts();
2324 // ui::ET_GESTURE_END events should not be seen by any view when there is
2325 // no default gesture handler set, but they should be marked as handled by
2326 // OnEventProcessingStarted().
2327 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2328 widget->OnGestureEvent(&end);
2329 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2330 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2331 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2332 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2333 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2334 EXPECT_TRUE(end.handled());
2335 v1->ResetCounts();
2336 v2->ResetCounts();
2337 v3->ResetCounts();
2338 v4->ResetCounts();
2340 // ui::ET_GESTURE_END events not corresponding to the release of the
2341 // final touch point should never be seen by any view, but they should
2342 // be marked as handled by OnEventProcessingStarted().
2343 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2344 details.set_touch_points(2);
2345 GestureEventForTest end_second_touch_point(details, 5, 5);
2346 widget->OnGestureEvent(&end_second_touch_point);
2347 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2348 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2349 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2350 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2351 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2352 EXPECT_TRUE(end_second_touch_point.handled());
2353 v1->ResetCounts();
2354 v2->ResetCounts();
2355 v3->ResetCounts();
2356 v4->ResetCounts();
2358 // ui::ET_GESTURE_SCROLL_UPDATE 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_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2362 widget->OnGestureEvent(&scroll_update);
2363 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2364 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2365 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2366 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2367 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2368 EXPECT_TRUE(scroll_update.handled());
2369 v1->ResetCounts();
2370 v2->ResetCounts();
2371 v3->ResetCounts();
2372 v4->ResetCounts();
2374 // ui::ET_GESTURE_SCROLL_END 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_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2378 widget->OnGestureEvent(&scroll_end);
2379 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2380 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2381 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2382 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2383 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2384 EXPECT_TRUE(scroll_end.handled());
2385 v1->ResetCounts();
2386 v2->ResetCounts();
2387 v3->ResetCounts();
2388 v4->ResetCounts();
2390 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2391 // there is no default gesture handler set, but they should be marked as
2392 // handled by OnEventProcessingStarted().
2393 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2394 widget->OnGestureEvent(&scroll_fling_start);
2395 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2396 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2397 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2398 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2399 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2400 EXPECT_TRUE(scroll_fling_start.handled());
2401 v1->ResetCounts();
2402 v2->ResetCounts();
2403 v3->ResetCounts();
2404 v4->ResetCounts();
2406 widget->Close();
2409 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2410 // in a view hierarchy and that the default gesture handler in RootView is set
2411 // correctly.
2412 TEST_F(WidgetTest, GestureEventDispatch) {
2413 Widget* widget = CreateTopLevelNativeWidget();
2414 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2416 // Define a hierarchy of four views (coordinates are in
2417 // their parent coordinate space).
2418 // v1 (0, 0, 300, 300)
2419 // v2 (0, 0, 100, 100)
2420 // v3 (0, 0, 50, 50)
2421 // v4(0, 0, 10, 10)
2422 EventCountView* v1 = new EventCountView();
2423 v1->SetBounds(0, 0, 300, 300);
2424 EventCountView* v2 = new EventCountView();
2425 v2->SetBounds(0, 0, 100, 100);
2426 EventCountView* v3 = new EventCountView();
2427 v3->SetBounds(0, 0, 50, 50);
2428 EventCountView* v4 = new EventCountView();
2429 v4->SetBounds(0, 0, 10, 10);
2430 internal::RootView* root_view =
2431 static_cast<internal::RootView*>(widget->GetRootView());
2432 root_view->AddChildView(v1);
2433 v1->AddChildView(v2);
2434 v2->AddChildView(v3);
2435 v3->AddChildView(v4);
2437 widget->Show();
2439 // No gesture handler is set in the root view and none of the views in the
2440 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2441 // event should be dispatched to all views in the hierarchy, the gesture
2442 // handler should remain unset, and the event should remain unhandled.
2443 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2444 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2445 widget->OnGestureEvent(&tap);
2446 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2447 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2448 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2449 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2450 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2451 EXPECT_FALSE(tap.handled());
2453 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2454 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2455 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2456 // and the event should be marked as handled.
2457 v1->ResetCounts();
2458 v2->ResetCounts();
2459 v3->ResetCounts();
2460 v4->ResetCounts();
2461 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2462 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2463 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2464 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2465 widget->OnGestureEvent(&tap);
2466 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2467 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2468 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2469 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2470 EXPECT_EQ(v3, GetGestureHandler(root_view));
2471 EXPECT_TRUE(tap.handled());
2473 // The gesture handler is set to |v3| and all views handle all gesture event
2474 // types. In this case subsequent gesture events should only be dispatched to
2475 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2476 v1->ResetCounts();
2477 v2->ResetCounts();
2478 v3->ResetCounts();
2479 v4->ResetCounts();
2480 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2481 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2482 widget->OnGestureEvent(&tap);
2483 EXPECT_TRUE(tap.handled());
2484 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2485 widget->OnGestureEvent(&show_press);
2486 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2487 widget->OnGestureEvent(&tap);
2488 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2489 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2490 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2491 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2492 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2493 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2494 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2495 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2496 EXPECT_TRUE(tap.handled());
2497 EXPECT_TRUE(show_press.handled());
2498 EXPECT_EQ(v3, GetGestureHandler(root_view));
2500 // The gesture handler is set to |v3|, but |v3| does not handle
2501 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2502 // only to |v3|, but the event should remain unhandled. The gesture handler
2503 // should remain as |v3|.
2504 v1->ResetCounts();
2505 v2->ResetCounts();
2506 v3->ResetCounts();
2507 v4->ResetCounts();
2508 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2509 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2510 widget->OnGestureEvent(&tap);
2511 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2512 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2513 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2514 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2515 EXPECT_FALSE(tap.handled());
2516 EXPECT_EQ(v3, GetGestureHandler(root_view));
2518 widget->Close();
2521 // Tests that gesture scroll events will change the default gesture handler in
2522 // RootView if the current handler to which they are dispatched does not handle
2523 // gesture scroll events.
2524 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2525 Widget* widget = CreateTopLevelNativeWidget();
2526 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2528 // Define a hierarchy of four views (coordinates are in
2529 // their parent coordinate space).
2530 // v1 (0, 0, 300, 300)
2531 // v2 (0, 0, 100, 100)
2532 // v3 (0, 0, 50, 50)
2533 // v4(0, 0, 10, 10)
2534 EventCountView* v1 = new EventCountView();
2535 v1->SetBounds(0, 0, 300, 300);
2536 EventCountView* v2 = new EventCountView();
2537 v2->SetBounds(0, 0, 100, 100);
2538 EventCountView* v3 = new EventCountView();
2539 v3->SetBounds(0, 0, 50, 50);
2540 EventCountView* v4 = new EventCountView();
2541 v4->SetBounds(0, 0, 10, 10);
2542 internal::RootView* root_view =
2543 static_cast<internal::RootView*>(widget->GetRootView());
2544 root_view->AddChildView(v1);
2545 v1->AddChildView(v2);
2546 v2->AddChildView(v3);
2547 v3->AddChildView(v4);
2549 widget->Show();
2551 // Change the handle mode of |v3| to indicate that it would like to handle
2552 // gesture events.
2553 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2555 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2556 // should bubble up the views hierarchy until it reaches the first view
2557 // that will handle it (|v3|) and then sets the handler to |v3|.
2558 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2559 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2560 widget->OnGestureEvent(&tap_down);
2561 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2562 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2563 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2564 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2565 EXPECT_EQ(v3, GetGestureHandler(root_view));
2566 EXPECT_TRUE(tap_down.handled());
2567 v1->ResetCounts();
2568 v2->ResetCounts();
2569 v3->ResetCounts();
2570 v4->ResetCounts();
2572 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2573 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2574 widget->OnGestureEvent(&tap_cancel);
2575 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2576 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2577 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2578 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2579 EXPECT_EQ(v3, GetGestureHandler(root_view));
2580 EXPECT_TRUE(tap_cancel.handled());
2581 v1->ResetCounts();
2582 v2->ResetCounts();
2583 v3->ResetCounts();
2584 v4->ResetCounts();
2586 // Change the handle mode of |v3| to indicate that it would no longer like
2587 // to handle events, and change the mode of |v1| to indicate that it would
2588 // like to handle events.
2589 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2590 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2592 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2593 // handler (|v3|) does not handle scroll events, the event should bubble up
2594 // the views hierarchy until it reaches the first view that will handle
2595 // it (|v1|) and then sets the handler to |v1|.
2596 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2597 widget->OnGestureEvent(&scroll_begin);
2598 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2599 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2600 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2601 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2602 EXPECT_EQ(v1, GetGestureHandler(root_view));
2603 EXPECT_TRUE(scroll_begin.handled());
2604 v1->ResetCounts();
2605 v2->ResetCounts();
2606 v3->ResetCounts();
2607 v4->ResetCounts();
2609 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2610 // directly.
2611 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2612 widget->OnGestureEvent(&scroll_update);
2613 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2614 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2615 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2616 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2617 EXPECT_EQ(v1, GetGestureHandler(root_view));
2618 EXPECT_TRUE(scroll_update.handled());
2619 v1->ResetCounts();
2620 v2->ResetCounts();
2621 v3->ResetCounts();
2622 v4->ResetCounts();
2624 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2625 // directly and should not reset the gesture handler.
2626 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2627 widget->OnGestureEvent(&scroll_end);
2628 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2629 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2630 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2631 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2632 EXPECT_EQ(v1, GetGestureHandler(root_view));
2633 EXPECT_TRUE(scroll_end.handled());
2634 v1->ResetCounts();
2635 v2->ResetCounts();
2636 v3->ResetCounts();
2637 v4->ResetCounts();
2639 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2640 // still be dispatched to |v1| directly.
2641 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2642 widget->OnGestureEvent(&pinch_begin);
2643 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2644 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2645 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2646 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2647 EXPECT_EQ(v1, GetGestureHandler(root_view));
2648 EXPECT_TRUE(pinch_begin.handled());
2649 v1->ResetCounts();
2650 v2->ResetCounts();
2651 v3->ResetCounts();
2652 v4->ResetCounts();
2654 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2655 // set the gesture handler to NULL.
2656 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2657 widget->OnGestureEvent(&end);
2658 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2659 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2660 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2661 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2662 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2663 EXPECT_TRUE(end.handled());
2665 widget->Close();
2668 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2669 // that when a gesture event bubbles up a View hierarchy, the location
2670 // of a gesture event seen by each View is in the local coordinate space
2671 // of that View.
2672 class GestureLocationView : public EventCountView {
2673 public:
2674 GestureLocationView() {}
2675 ~GestureLocationView() override {}
2677 void set_expected_location(gfx::Point expected_location) {
2678 expected_location_ = expected_location;
2681 // EventCountView:
2682 void OnGestureEvent(ui::GestureEvent* event) override {
2683 EventCountView::OnGestureEvent(event);
2685 // Verify that the location of |event| is in the local coordinate
2686 // space of |this|.
2687 EXPECT_EQ(expected_location_, event->location());
2690 private:
2691 // The expected location of a gesture event dispatched to |this|.
2692 gfx::Point expected_location_;
2694 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2697 // Verifies that the location of a gesture event is always in the local
2698 // coordinate space of the View receiving the event while bubbling.
2699 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2700 Widget* widget = CreateTopLevelNativeWidget();
2701 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2703 // Define a hierarchy of three views (coordinates shown below are in the
2704 // coordinate space of the root view, but the coordinates used for
2705 // SetBounds() are in their parent coordinate space).
2706 // v1 (50, 50, 150, 150)
2707 // v2 (100, 70, 50, 80)
2708 // v3 (120, 100, 10, 10)
2709 GestureLocationView* v1 = new GestureLocationView();
2710 v1->SetBounds(50, 50, 150, 150);
2711 GestureLocationView* v2 = new GestureLocationView();
2712 v2->SetBounds(50, 20, 50, 80);
2713 GestureLocationView* v3 = new GestureLocationView();
2714 v3->SetBounds(20, 30, 10, 10);
2715 internal::RootView* root_view =
2716 static_cast<internal::RootView*>(widget->GetRootView());
2717 root_view->AddChildView(v1);
2718 v1->AddChildView(v2);
2719 v2->AddChildView(v3);
2721 widget->Show();
2723 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2724 // This event is contained within all of |v1|, |v2|, and |v3|.
2725 gfx::Point location_in_root(125, 105);
2726 GestureEventForTest tap(
2727 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2729 // Calculate the location of the event in the local coordinate spaces
2730 // of each of the views.
2731 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2732 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2733 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2734 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2735 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2736 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2738 // Dispatch the event. When each view receives the event, its location should
2739 // be in the local coordinate space of that view (see the check made by
2740 // GestureLocationView). After dispatch is complete the event's location
2741 // should be in the root coordinate space.
2742 v1->set_expected_location(location_in_v1);
2743 v2->set_expected_location(location_in_v2);
2744 v3->set_expected_location(location_in_v3);
2745 widget->OnGestureEvent(&tap);
2746 EXPECT_EQ(location_in_root, tap.location());
2748 // Verify that each view did in fact see the event.
2749 EventCountView* view1 = v1;
2750 EventCountView* view2 = v2;
2751 EventCountView* view3 = v3;
2752 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2753 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2754 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2756 widget->Close();
2759 // Verifies that disabled views are permitted to be set as the default gesture
2760 // handler in RootView. Also verifies that gesture events targeted to a disabled
2761 // view are not actually dispatched to the view, but are still marked as
2762 // handled.
2763 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2764 Widget* widget = CreateTopLevelNativeWidget();
2765 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2767 // Define a hierarchy of four views (coordinates are in
2768 // their parent coordinate space).
2769 // v1 (0, 0, 300, 300)
2770 // v2 (0, 0, 100, 100)
2771 // v3 (0, 0, 50, 50)
2772 // v4(0, 0, 10, 10)
2773 EventCountView* v1 = new EventCountView();
2774 v1->SetBounds(0, 0, 300, 300);
2775 EventCountView* v2 = new EventCountView();
2776 v2->SetBounds(0, 0, 100, 100);
2777 EventCountView* v3 = new EventCountView();
2778 v3->SetBounds(0, 0, 50, 50);
2779 EventCountView* v4 = new EventCountView();
2780 v4->SetBounds(0, 0, 10, 10);
2781 internal::RootView* root_view =
2782 static_cast<internal::RootView*>(widget->GetRootView());
2783 root_view->AddChildView(v1);
2784 v1->AddChildView(v2);
2785 v2->AddChildView(v3);
2786 v3->AddChildView(v4);
2788 widget->Show();
2790 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2791 // disabled.
2792 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2793 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2794 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2795 v3->SetEnabled(false);
2797 // No gesture handler is set in the root view. In this case the tap event
2798 // should be dispatched only to |v4|, the gesture handler should be set to
2799 // |v3|, and the event should be marked as handled.
2800 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2801 widget->OnGestureEvent(&tap);
2802 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2803 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2804 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2805 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2806 EXPECT_EQ(v3, GetGestureHandler(root_view));
2807 EXPECT_TRUE(tap.handled());
2808 v1->ResetCounts();
2809 v2->ResetCounts();
2810 v3->ResetCounts();
2811 v4->ResetCounts();
2813 // A subsequent gesture event should be marked as handled but not dispatched.
2814 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2815 widget->OnGestureEvent(&tap);
2816 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2817 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2818 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2819 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2820 EXPECT_EQ(v3, GetGestureHandler(root_view));
2821 EXPECT_TRUE(tap.handled());
2822 v1->ResetCounts();
2823 v2->ResetCounts();
2824 v3->ResetCounts();
2825 v4->ResetCounts();
2827 // A GESTURE_END should reset the default gesture handler to NULL. It should
2828 // also not be dispatched to |v3| but still marked as handled.
2829 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2830 widget->OnGestureEvent(&end);
2831 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2832 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2833 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2834 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2835 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2836 EXPECT_TRUE(end.handled());
2837 v1->ResetCounts();
2838 v2->ResetCounts();
2839 v3->ResetCounts();
2840 v4->ResetCounts();
2842 // Change the handle mode of |v3| to indicate that it would no longer like
2843 // to handle events which are dispatched to it.
2844 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2846 // No gesture handler is set in the root view. In this case the tap event
2847 // should be dispatched only to |v4| and the event should be marked as
2848 // handled. Furthermore, the gesture handler should be set to
2849 // |v3|; even though |v3| does not explicitly handle events, it is a
2850 // valid target for the tap event because it is disabled.
2851 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2852 widget->OnGestureEvent(&tap);
2853 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2854 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2855 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2856 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2857 EXPECT_EQ(v3, GetGestureHandler(root_view));
2858 EXPECT_TRUE(tap.handled());
2859 v1->ResetCounts();
2860 v2->ResetCounts();
2861 v3->ResetCounts();
2862 v4->ResetCounts();
2864 // A GESTURE_END should reset the default gesture handler to NULL. It should
2865 // also not be dispatched to |v3| but still marked as handled.
2866 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2867 widget->OnGestureEvent(&end);
2868 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2869 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2870 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2871 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2872 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2873 EXPECT_TRUE(end.handled());
2875 widget->Close();
2878 // Test the result of Widget::GetAllChildWidgets().
2879 TEST_F(WidgetTest, GetAllChildWidgets) {
2880 // Create the following widget hierarchy:
2882 // toplevel
2883 // +-- w1
2884 // +-- w11
2885 // +-- w2
2886 // +-- w21
2887 // +-- w22
2888 Widget* toplevel = CreateTopLevelPlatformWidget();
2889 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2890 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2891 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2892 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2893 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2895 std::set<Widget*> expected;
2896 expected.insert(toplevel);
2897 expected.insert(w1);
2898 expected.insert(w11);
2899 expected.insert(w2);
2900 expected.insert(w21);
2901 expected.insert(w22);
2903 std::set<Widget*> widgets;
2904 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2906 EXPECT_EQ(expected.size(), widgets.size());
2907 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2908 toplevel->CloseNow();
2911 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2912 // a vector.
2913 class DestroyedTrackingView : public View {
2914 public:
2915 DestroyedTrackingView(const std::string& name,
2916 std::vector<std::string>* add_to)
2917 : name_(name),
2918 add_to_(add_to) {
2921 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2923 private:
2924 const std::string name_;
2925 std::vector<std::string>* add_to_;
2927 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2930 class WidgetChildDestructionTest : public WidgetTest {
2931 public:
2932 WidgetChildDestructionTest() {}
2934 // Creates a top level and a child, destroys the child and verifies the views
2935 // of the child are destroyed before the views of the parent.
2936 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2937 bool child_has_desktop_native_widget_aura) {
2938 // When a View is destroyed its name is added here.
2939 std::vector<std::string> destroyed;
2941 Widget* top_level = new Widget;
2942 Widget::InitParams params =
2943 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2944 #if !defined(OS_CHROMEOS)
2945 if (top_level_has_desktop_native_widget_aura)
2946 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2947 #endif
2948 top_level->Init(params);
2949 top_level->GetRootView()->AddChildView(
2950 new DestroyedTrackingView("parent", &destroyed));
2951 top_level->Show();
2953 Widget* child = new Widget;
2954 Widget::InitParams child_params =
2955 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2956 child_params.parent = top_level->GetNativeView();
2957 #if !defined(OS_CHROMEOS)
2958 if (child_has_desktop_native_widget_aura)
2959 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2960 #endif
2961 child->Init(child_params);
2962 child->GetRootView()->AddChildView(
2963 new DestroyedTrackingView("child", &destroyed));
2964 child->Show();
2966 // Should trigger destruction of the child too.
2967 top_level->native_widget_private()->CloseNow();
2969 // Child should be destroyed first.
2970 ASSERT_EQ(2u, destroyed.size());
2971 EXPECT_EQ("child", destroyed[0]);
2972 EXPECT_EQ("parent", destroyed[1]);
2975 private:
2976 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2979 #if !defined(OS_CHROMEOS)
2980 // See description of RunDestroyChildWidgetsTest(). Parent uses
2981 // DesktopNativeWidgetAura.
2982 TEST_F(WidgetChildDestructionTest,
2983 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2984 RunDestroyChildWidgetsTest(true, false);
2987 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2988 // DesktopNativeWidgetAura.
2989 TEST_F(WidgetChildDestructionTest,
2990 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2991 RunDestroyChildWidgetsTest(true, true);
2993 #endif // !defined(OS_CHROMEOS)
2995 // See description of RunDestroyChildWidgetsTest().
2996 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2997 RunDestroyChildWidgetsTest(false, false);
3000 // Verifies nativeview visbility matches that of Widget visibility when
3001 // SetFullscreen is invoked.
3002 TEST_F(WidgetTest, FullscreenStatePropagated) {
3003 Widget::InitParams init_params =
3004 CreateParams(Widget::InitParams::TYPE_WINDOW);
3005 init_params.show_state = ui::SHOW_STATE_NORMAL;
3006 init_params.bounds = gfx::Rect(0, 0, 500, 500);
3007 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3010 Widget top_level_widget;
3011 top_level_widget.Init(init_params);
3012 top_level_widget.SetFullscreen(true);
3013 EXPECT_EQ(top_level_widget.IsVisible(),
3014 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3015 top_level_widget.CloseNow();
3017 #if !defined(OS_CHROMEOS)
3019 Widget top_level_widget;
3020 init_params.native_widget =
3021 new PlatformDesktopNativeWidget(&top_level_widget);
3022 top_level_widget.Init(init_params);
3023 top_level_widget.SetFullscreen(true);
3024 EXPECT_EQ(top_level_widget.IsVisible(),
3025 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3026 top_level_widget.CloseNow();
3028 #endif
3031 namespace {
3033 class FullscreenAwareFrame : public views::NonClientFrameView {
3034 public:
3035 explicit FullscreenAwareFrame(views::Widget* widget)
3036 : widget_(widget), fullscreen_layout_called_(false) {}
3037 ~FullscreenAwareFrame() override {}
3039 // views::NonClientFrameView overrides:
3040 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3041 gfx::Rect GetWindowBoundsForClientBounds(
3042 const gfx::Rect& client_bounds) const override {
3043 return gfx::Rect();
3045 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3046 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3047 void ResetWindowControls() override {}
3048 void UpdateWindowIcon() override {}
3049 void UpdateWindowTitle() override {}
3050 void SizeConstraintsChanged() override {}
3052 // views::View overrides:
3053 void Layout() override {
3054 if (widget_->IsFullscreen())
3055 fullscreen_layout_called_ = true;
3058 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3060 private:
3061 views::Widget* widget_;
3062 bool fullscreen_layout_called_;
3064 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3067 } // namespace
3069 // Tests that frame Layout is called when a widget goes fullscreen without
3070 // changing its size or title.
3071 TEST_F(WidgetTest, FullscreenFrameLayout) {
3072 Widget* widget = CreateTopLevelPlatformWidget();
3073 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3074 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3076 widget->Maximize();
3077 RunPendingMessages();
3079 EXPECT_FALSE(frame->fullscreen_layout_called());
3080 widget->SetFullscreen(true);
3081 widget->Show();
3082 RunPendingMessages();
3084 if (IsTestingSnowLeopard()) {
3085 // Fullscreen is currently ignored on Snow Leopard.
3086 EXPECT_FALSE(frame->fullscreen_layout_called());
3087 } else {
3088 EXPECT_TRUE(frame->fullscreen_layout_called());
3091 widget->CloseNow();
3094 #if !defined(OS_CHROMEOS)
3095 namespace {
3097 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3098 // OnWindowDestroying.
3099 class IsActiveFromDestroyObserver : public WidgetObserver {
3100 public:
3101 IsActiveFromDestroyObserver() {}
3102 ~IsActiveFromDestroyObserver() override {}
3103 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3105 private:
3106 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3109 } // namespace
3111 // Verifies Widget::IsActive() invoked from
3112 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3113 TEST_F(WidgetTest, IsActiveFromDestroy) {
3114 // Create two widgets, one a child of the other.
3115 IsActiveFromDestroyObserver observer;
3116 Widget parent_widget;
3117 Widget::InitParams parent_params =
3118 CreateParams(Widget::InitParams::TYPE_POPUP);
3119 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3120 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3121 parent_widget.Init(parent_params);
3122 parent_widget.Show();
3124 Widget child_widget;
3125 Widget::InitParams child_params =
3126 CreateParams(Widget::InitParams::TYPE_POPUP);
3127 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3128 child_params.context = parent_widget.GetNativeWindow();
3129 child_widget.Init(child_params);
3130 child_widget.AddObserver(&observer);
3131 child_widget.Show();
3133 parent_widget.CloseNow();
3135 #endif // !defined(OS_CHROMEOS)
3137 // Tests that events propagate through from the dispatcher with the correct
3138 // event type, and that the different platforms behave the same.
3139 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3140 EventCountView* view = new EventCountView;
3141 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3142 view->SetBounds(10, 10, 50, 40);
3144 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3145 widget->GetRootView()->AddChildView(view);
3147 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3148 widget->Show();
3150 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3151 generator.set_current_location(gfx::Point(20, 20));
3153 generator.ClickLeftButton();
3154 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3155 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3156 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3158 generator.PressRightButton();
3159 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3160 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3161 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3163 generator.ReleaseRightButton();
3164 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3165 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3166 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3168 // Test mouse move events.
3169 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3170 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3172 // Move the mouse within the view (20, 20) -> (30, 30).
3173 generator.MoveMouseTo(gfx::Point(30, 30));
3174 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3175 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3176 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3178 // Move it again - entered count shouldn't change.
3179 generator.MoveMouseTo(gfx::Point(31, 31));
3180 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3181 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3182 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3184 // Move it off the view.
3185 generator.MoveMouseTo(gfx::Point(5, 5));
3186 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3187 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3188 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3190 // Move it back on.
3191 generator.MoveMouseTo(gfx::Point(20, 20));
3192 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3193 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3194 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3196 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3197 generator.DragMouseTo(gfx::Point(40, 40));
3198 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3199 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3200 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3201 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3203 widget->CloseNow();
3206 // Tests that the root view is correctly set up for Widget types that do not
3207 // require a non-client view, before any other views are added to the widget.
3208 // That is, before Widget::ReorderNativeViews() is called which, if called with
3209 // a root view not set, could cause the root view to get resized to the widget.
3210 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3211 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3212 View* root_view = widget->GetRootView();
3214 // Size the root view to exceed the widget bounds.
3215 const gfx::Rect test_rect(0, 0, 500, 500);
3216 root_view->SetBoundsRect(test_rect);
3218 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3220 EXPECT_EQ(test_rect, root_view->bounds());
3221 widget->ReorderNativeViews();
3222 EXPECT_EQ(test_rect, root_view->bounds());
3224 widget->CloseNow();
3227 #if defined(OS_WIN)
3228 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3229 // messages via the WindowEventTarget interface implemented by the
3230 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3231 // event
3232 TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
3233 Widget widget;
3234 Widget::InitParams params =
3235 CreateParams(Widget::InitParams::TYPE_WINDOW);
3236 params.native_widget = new PlatformDesktopNativeWidget(&widget);
3237 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3238 widget.Init(params);
3239 widget.Show();
3241 ui::WindowEventTarget* target =
3242 reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
3243 widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3244 ui::WindowEventTarget::kWin32InputEventTarget));
3245 EXPECT_NE(nullptr, target);
3246 bool handled = false;
3247 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled);
3248 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled);
3249 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled);
3250 widget.CloseNow();
3252 #endif
3254 // Test that SetAlwaysOnTop and IsAlwaysOnTop are consistent.
3255 TEST_F(WidgetTest, AlwaysOnTop) {
3256 Widget* widget = CreateTopLevelNativeWidget();
3257 EXPECT_FALSE(widget->IsAlwaysOnTop());
3258 widget->SetAlwaysOnTop(true);
3259 EXPECT_TRUE(widget->IsAlwaysOnTop());
3260 widget->SetAlwaysOnTop(false);
3261 EXPECT_FALSE(widget->IsAlwaysOnTop());
3262 widget->CloseNow();
3265 } // namespace test
3266 } // namespace views