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.
8 #include "base/basictypes.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_processor.h"
20 #include "ui/events/event_utils.h"
21 #include "ui/events/test/event_generator.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/gfx/point.h"
24 #include "ui/views/bubble/bubble_delegate.h"
25 #include "ui/views/controls/textfield/textfield.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/views_delegate.h"
29 #include "ui/views/widget/native_widget_delegate.h"
30 #include "ui/views/widget/root_view.h"
31 #include "ui/views/widget/widget_deletion_observer.h"
32 #include "ui/views/window/dialog_delegate.h"
33 #include "ui/views/window/native_frame_view.h"
36 #include "ui/views/win/hwnd_util.h"
44 // TODO(tdanderson): This utility function is used in different unittest
45 // files. Move to a common location to avoid
47 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
49 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
55 // A view that keeps track of the events it receives, optionally consuming them.
56 class EventCountView : public View {
58 // Whether to call SetHandled() on events as they are received. For some event
59 // types, this will allow EventCountView to receives future events in the
60 // event sequence, such as a drag.
68 handle_mode_(PROPAGATE_EVENTS) {}
70 ~EventCountView() override {}
72 int GetEventCount(ui::EventType type) {
73 return event_count_[type];
80 int last_flags() const {
84 void set_handle_mode(HandleMode handle_mode) {
85 handle_mode_ = handle_mode;
89 // Overridden from View:
90 void OnMouseMoved(const ui::MouseEvent& event) override {
91 // MouseMove events are not re-dispatched from the RootView.
92 ++event_count_[ui::ET_MOUSE_MOVED];
96 // Overridden from ui::EventHandler:
97 void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); }
98 void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); }
99 void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); }
100 void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); }
103 void RecordEvent(ui::Event* event) {
104 ++event_count_[event->type()];
105 last_flags_ = event->flags();
106 if (handle_mode_ == CONSUME_EVENTS)
110 std::map<ui::EventType, int> event_count_;
112 HandleMode handle_mode_;
114 DISALLOW_COPY_AND_ASSIGN(EventCountView);
117 // A view that keeps track of the events it receives, and consumes all scroll
118 // gesture events and ui::ET_SCROLL events.
119 class ScrollableEventCountView : public EventCountView {
121 ScrollableEventCountView() {}
122 ~ScrollableEventCountView() override {}
125 // Overridden from ui::EventHandler:
126 void OnGestureEvent(ui::GestureEvent* event) override {
127 EventCountView::OnGestureEvent(event);
128 switch (event->type()) {
129 case ui::ET_GESTURE_SCROLL_BEGIN:
130 case ui::ET_GESTURE_SCROLL_UPDATE:
131 case ui::ET_GESTURE_SCROLL_END:
132 case ui::ET_SCROLL_FLING_START:
140 void OnScrollEvent(ui::ScrollEvent* event) override {
141 EventCountView::OnScrollEvent(event);
142 if (event->type() == ui::ET_SCROLL)
146 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
149 // A view that implements GetMinimumSize.
150 class MinimumSizeFrameView : public NativeFrameView {
152 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
153 ~MinimumSizeFrameView() override {}
156 // Overridden from View:
157 gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
159 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
162 // An event handler that simply keeps a count of the different types of events
164 class EventCountHandler : public ui::EventHandler {
166 EventCountHandler() {}
167 ~EventCountHandler() override {}
169 int GetEventCount(ui::EventType type) {
170 return event_count_[type];
174 event_count_.clear();
178 // Overridden from ui::EventHandler:
179 void OnEvent(ui::Event* event) override {
181 ui::EventHandler::OnEvent(event);
185 void RecordEvent(const ui::Event& event) {
186 ++event_count_[event.type()];
189 std::map<ui::EventType, int> event_count_;
191 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
194 // Class that closes the widget (which ends up deleting it immediately) when the
195 // appropriate event is received.
196 class CloseWidgetView : public View {
198 explicit CloseWidgetView(ui::EventType event_type)
199 : event_type_(event_type) {
202 // ui::EventHandler override:
203 void OnEvent(ui::Event* event) override {
204 if (event->type() == event_type_) {
205 // Go through NativeWidgetPrivate to simulate what happens if the OS
206 // deletes the NativeWindow out from under us.
207 GetWidget()->native_widget_private()->CloseNow();
209 View::OnEvent(event);
210 if (!event->IsTouchEvent())
216 const ui::EventType event_type_;
218 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
221 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
222 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
223 // because the former is implemented on all platforms but the latter is not.
224 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
225 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
226 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
227 widget->IsActive() ? ui::SHOW_STATE_NORMAL :
228 ui::SHOW_STATE_INACTIVE;
231 TEST_F(WidgetTest, WidgetInitParams) {
232 // Widgets are not transparent by default.
233 Widget::InitParams init1;
234 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
237 ////////////////////////////////////////////////////////////////////////////////
238 // Widget::GetTopLevelWidget tests.
240 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
241 // Create a hierarchy of native widgets.
242 Widget* toplevel = CreateTopLevelPlatformWidget();
243 gfx::NativeView parent = toplevel->GetNativeView();
244 Widget* child = CreateChildPlatformWidget(parent);
246 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
247 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
249 toplevel->CloseNow();
250 // |child| should be automatically destroyed with |toplevel|.
253 // Test if a focus manager and an inputmethod work without CHECK failure
254 // when window activation changes.
255 TEST_F(WidgetTest, ChangeActivation) {
256 Widget* top1 = CreateTopLevelPlatformWidget();
257 // CreateInputMethod before activated
258 top1->GetInputMethod();
260 RunPendingMessages();
262 Widget* top2 = CreateTopLevelPlatformWidget();
264 RunPendingMessages();
267 RunPendingMessages();
269 // Create InputMethod after deactivated.
270 top2->GetInputMethod();
272 RunPendingMessages();
275 RunPendingMessages();
281 // Tests visibility of child widgets.
282 TEST_F(WidgetTest, Visibility) {
283 Widget* toplevel = CreateTopLevelPlatformWidget();
284 gfx::NativeView parent = toplevel->GetNativeView();
285 Widget* child = CreateChildPlatformWidget(parent);
287 EXPECT_FALSE(toplevel->IsVisible());
288 EXPECT_FALSE(child->IsVisible());
292 EXPECT_FALSE(toplevel->IsVisible());
293 EXPECT_FALSE(child->IsVisible());
297 EXPECT_TRUE(toplevel->IsVisible());
298 EXPECT_TRUE(child->IsVisible());
300 toplevel->CloseNow();
301 // |child| should be automatically destroyed with |toplevel|.
304 ////////////////////////////////////////////////////////////////////////////////
305 // Widget ownership tests.
307 // Tests various permutations of Widget ownership specified in the
308 // InitParams::Ownership param.
310 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
311 class WidgetOwnershipTest : public WidgetTest {
313 WidgetOwnershipTest() {}
314 ~WidgetOwnershipTest() override {}
316 void SetUp() override {
318 desktop_widget_ = CreateTopLevelPlatformWidget();
321 void TearDown() override {
322 desktop_widget_->CloseNow();
323 WidgetTest::TearDown();
327 Widget* desktop_widget_;
329 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
332 // A bag of state to monitor destructions.
333 struct OwnershipTestState {
334 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
337 bool native_widget_deleted;
340 // A platform NativeWidget subclass that updates a bag of state when it is
342 class OwnershipTestNativeWidget : public PlatformNativeWidget {
344 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
345 OwnershipTestState* state)
346 : PlatformNativeWidget(delegate),
349 ~OwnershipTestNativeWidget() override {
350 state_->native_widget_deleted = true;
354 OwnershipTestState* state_;
356 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
359 // A views NativeWidget subclass that updates a bag of state when it is
361 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
363 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
364 OwnershipTestState* state)
365 : NativeWidgetCapture(delegate),
368 ~OwnershipTestNativeWidgetAura() override {
369 state_->native_widget_deleted = true;
373 OwnershipTestState* state_;
375 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
378 // A Widget subclass that updates a bag of state when it is destroyed.
379 class OwnershipTestWidget : public Widget {
381 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
382 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
385 OwnershipTestState* state_;
387 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
390 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
392 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
393 OwnershipTestState state;
395 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
396 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
397 params.native_widget =
398 new OwnershipTestNativeWidgetAura(widget.get(), &state);
399 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
400 widget->Init(params);
402 // Now delete the Widget, which should delete the NativeWidget.
405 EXPECT_TRUE(state.widget_deleted);
406 EXPECT_TRUE(state.native_widget_deleted);
408 // TODO(beng): write test for this ownership scenario and the NativeWidget
409 // being deleted out from under the Widget.
412 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
413 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
414 OwnershipTestState state;
416 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
417 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
418 params.native_widget =
419 new OwnershipTestNativeWidgetAura(widget.get(), &state);
420 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
421 widget->Init(params);
423 // Now delete the Widget, which should delete the NativeWidget.
426 EXPECT_TRUE(state.widget_deleted);
427 EXPECT_TRUE(state.native_widget_deleted);
429 // TODO(beng): write test for this ownership scenario and the NativeWidget
430 // being deleted out from under the Widget.
433 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
434 // destroy the parent view.
435 TEST_F(WidgetOwnershipTest,
436 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
437 OwnershipTestState state;
439 Widget* toplevel = CreateTopLevelPlatformWidget();
441 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
442 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
443 params.native_widget =
444 new OwnershipTestNativeWidgetAura(widget.get(), &state);
445 params.parent = toplevel->GetNativeView();
446 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
447 widget->Init(params);
449 // Now close the toplevel, which deletes the view hierarchy.
450 toplevel->CloseNow();
452 RunPendingMessages();
454 // This shouldn't delete the widget because it shouldn't be deleted
455 // from the native side.
456 EXPECT_FALSE(state.widget_deleted);
457 EXPECT_FALSE(state.native_widget_deleted);
459 // Now delete it explicitly.
462 EXPECT_TRUE(state.widget_deleted);
463 EXPECT_TRUE(state.native_widget_deleted);
466 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
468 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
469 OwnershipTestState state;
471 Widget* widget = new OwnershipTestWidget(&state);
472 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
473 params.native_widget =
474 new OwnershipTestNativeWidgetAura(widget, &state);
475 widget->Init(params);
477 // Now destroy the native widget.
480 EXPECT_TRUE(state.widget_deleted);
481 EXPECT_TRUE(state.native_widget_deleted);
484 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
485 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
486 OwnershipTestState state;
488 Widget* toplevel = CreateTopLevelPlatformWidget();
490 Widget* widget = new OwnershipTestWidget(&state);
491 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
492 params.native_widget =
493 new OwnershipTestNativeWidgetAura(widget, &state);
494 params.parent = toplevel->GetNativeView();
495 widget->Init(params);
497 // Now destroy the native widget. This is achieved by closing the toplevel.
498 toplevel->CloseNow();
500 // The NativeWidget won't be deleted until after a return to the message loop
501 // so we have to run pending messages before testing the destruction status.
502 RunPendingMessages();
504 EXPECT_TRUE(state.widget_deleted);
505 EXPECT_TRUE(state.native_widget_deleted);
508 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
509 // widget, destroyed out from under it by the OS.
510 TEST_F(WidgetOwnershipTest,
511 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
512 OwnershipTestState state;
514 Widget* widget = new OwnershipTestWidget(&state);
515 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
516 params.native_widget =
517 new OwnershipTestNativeWidgetAura(widget, &state);
518 widget->Init(params);
520 // Now simulate a destroy of the platform native widget from the OS:
521 SimulateNativeDestroy(widget);
523 EXPECT_TRUE(state.widget_deleted);
524 EXPECT_TRUE(state.native_widget_deleted);
527 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
528 // destroyed by the view hierarchy that contains it.
529 TEST_F(WidgetOwnershipTest,
530 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
531 OwnershipTestState state;
533 Widget* toplevel = CreateTopLevelPlatformWidget();
535 Widget* widget = new OwnershipTestWidget(&state);
536 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
537 params.native_widget =
538 new OwnershipTestNativeWidgetAura(widget, &state);
539 params.parent = toplevel->GetNativeView();
540 widget->Init(params);
542 // Destroy the widget (achieved by closing the toplevel).
543 toplevel->CloseNow();
545 // The NativeWidget won't be deleted until after a return to the message loop
546 // so we have to run pending messages before testing the destruction status.
547 RunPendingMessages();
549 EXPECT_TRUE(state.widget_deleted);
550 EXPECT_TRUE(state.native_widget_deleted);
553 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
554 // we close it directly.
555 TEST_F(WidgetOwnershipTest,
556 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
557 OwnershipTestState state;
559 Widget* toplevel = CreateTopLevelPlatformWidget();
561 Widget* widget = new OwnershipTestWidget(&state);
562 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
563 params.native_widget =
564 new OwnershipTestNativeWidgetAura(widget, &state);
565 params.parent = toplevel->GetNativeView();
566 widget->Init(params);
568 // Destroy the widget.
570 toplevel->CloseNow();
572 // The NativeWidget won't be deleted until after a return to the message loop
573 // so we have to run pending messages before testing the destruction status.
574 RunPendingMessages();
576 EXPECT_TRUE(state.widget_deleted);
577 EXPECT_TRUE(state.native_widget_deleted);
580 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
581 TEST_F(WidgetOwnershipTest,
582 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
583 OwnershipTestState state;
585 WidgetDelegateView* delegate_view = new WidgetDelegateView;
587 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
588 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
589 params.native_widget =
590 new OwnershipTestNativeWidgetAura(widget.get(), &state);
591 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
592 params.delegate = delegate_view;
593 widget->Init(params);
594 widget->SetContentsView(delegate_view);
596 // Now delete the Widget. There should be no crash or use-after-free.
599 EXPECT_TRUE(state.widget_deleted);
600 EXPECT_TRUE(state.native_widget_deleted);
603 ////////////////////////////////////////////////////////////////////////////////
604 // Test to verify using various Widget methods doesn't crash when the underlying
605 // NativeView is destroyed.
607 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
609 WidgetWithDestroyedNativeViewTest() {}
610 ~WidgetWithDestroyedNativeViewTest() override {}
612 void InvokeWidgetMethods(Widget* widget) {
613 widget->GetNativeView();
614 widget->GetNativeWindow();
615 ui::Accelerator accelerator;
616 widget->GetAccelerator(0, &accelerator);
617 widget->GetTopLevelWidget();
618 widget->GetWindowBoundsInScreen();
619 widget->GetClientAreaBoundsInScreen();
620 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
621 widget->SetSize(gfx::Size(10, 11));
622 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
623 widget->SetVisibilityChangedAnimationsEnabled(false);
624 widget->StackAtTop();
629 widget->Deactivate();
631 widget->DisableInactiveRendering();
632 widget->SetAlwaysOnTop(true);
633 widget->IsAlwaysOnTop();
637 widget->IsMaximized();
638 widget->IsFullscreen();
639 widget->SetOpacity(0);
640 widget->SetUseDragFrame(true);
641 widget->FlashFrame(true);
643 widget->GetThemeProvider();
644 widget->GetNativeTheme();
645 widget->GetFocusManager();
646 widget->GetInputMethod();
647 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
648 widget->IsMouseEventsEnabled();
649 widget->SetNativeWindowProperty("xx", widget);
650 widget->GetNativeWindowProperty("xx");
651 widget->GetFocusTraversable();
653 widget->ReorderNativeViews();
654 widget->SetCapture(widget->GetRootView());
655 widget->ReleaseCapture();
656 widget->HasCapture();
657 widget->GetWorkAreaBoundsInScreen();
658 widget->IsTranslucentWindowOpacitySupported();
662 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
665 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
668 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
669 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
673 widget.native_widget_private()->CloseNow();
674 InvokeWidgetMethods(&widget);
676 #if !defined(OS_CHROMEOS)
679 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
680 params.native_widget = new PlatformDesktopNativeWidget(&widget);
681 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
685 widget.native_widget_private()->CloseNow();
686 InvokeWidgetMethods(&widget);
691 ////////////////////////////////////////////////////////////////////////////////
692 // Widget observer tests.
695 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
699 widget_closed_(NULL),
700 widget_activated_(NULL),
702 widget_hidden_(NULL),
703 widget_bounds_changed_(NULL) {
706 ~WidgetObserverTest() override {}
708 // Overridden from WidgetObserver:
709 void OnWidgetDestroying(Widget* widget) override {
710 if (active_ == widget)
712 widget_closed_ = widget;
715 void OnWidgetActivationChanged(Widget* widget, bool active) override {
717 if (widget_activated_)
718 widget_activated_->Deactivate();
719 widget_activated_ = widget;
722 if (widget_activated_ == widget)
723 widget_activated_ = NULL;
724 widget_deactivated_ = widget;
728 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
730 widget_shown_ = widget;
732 widget_hidden_ = widget;
735 void OnWidgetBoundsChanged(Widget* widget,
736 const gfx::Rect& new_bounds) override {
737 widget_bounds_changed_ = widget;
742 widget_closed_ = NULL;
743 widget_activated_ = NULL;
744 widget_deactivated_ = NULL;
745 widget_shown_ = NULL;
746 widget_hidden_ = NULL;
747 widget_bounds_changed_ = NULL;
750 Widget* NewWidget() {
751 Widget* widget = CreateTopLevelNativeWidget();
752 widget->AddObserver(this);
756 const Widget* active() const { return active_; }
757 const Widget* widget_closed() const { return widget_closed_; }
758 const Widget* widget_activated() const { return widget_activated_; }
759 const Widget* widget_deactivated() const { return widget_deactivated_; }
760 const Widget* widget_shown() const { return widget_shown_; }
761 const Widget* widget_hidden() const { return widget_hidden_; }
762 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
767 Widget* widget_closed_;
768 Widget* widget_activated_;
769 Widget* widget_deactivated_;
770 Widget* widget_shown_;
771 Widget* widget_hidden_;
772 Widget* widget_bounds_changed_;
775 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
776 Widget* toplevel = CreateTopLevelPlatformWidget();
778 Widget* toplevel1 = NewWidget();
779 Widget* toplevel2 = NewWidget();
786 toplevel1->Activate();
788 RunPendingMessages();
789 EXPECT_EQ(toplevel1, widget_activated());
791 toplevel2->Activate();
792 RunPendingMessages();
793 EXPECT_EQ(toplevel1, widget_deactivated());
794 EXPECT_EQ(toplevel2, widget_activated());
795 EXPECT_EQ(toplevel2, active());
797 toplevel->CloseNow();
800 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
801 Widget* toplevel = CreateTopLevelPlatformWidget();
803 Widget* child1 = NewWidget();
804 Widget* child2 = NewWidget();
813 EXPECT_EQ(child1, widget_hidden());
816 EXPECT_EQ(child2, widget_hidden());
819 EXPECT_EQ(child1, widget_shown());
822 EXPECT_EQ(child2, widget_shown());
824 toplevel->CloseNow();
827 TEST_F(WidgetObserverTest, DestroyBubble) {
828 Widget* anchor = CreateTopLevelPlatformWidget();
831 BubbleDelegateView* bubble_delegate =
832 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
833 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
834 bubble_widget->Show();
835 bubble_widget->CloseNow();
841 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
842 Widget* child1 = NewWidget();
843 Widget* child2 = NewWidget();
845 child1->OnNativeWidgetMove();
846 EXPECT_EQ(child1, widget_bounds_changed());
848 child2->OnNativeWidgetMove();
849 EXPECT_EQ(child2, widget_bounds_changed());
851 child1->OnNativeWidgetSizeChanged(gfx::Size());
852 EXPECT_EQ(child1, widget_bounds_changed());
854 child2->OnNativeWidgetSizeChanged(gfx::Size());
855 EXPECT_EQ(child2, widget_bounds_changed());
858 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
859 // widget is visible and not maximized or fullscreen.
860 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
861 // Choose test coordinates away from edges and dimensions that are "small"
862 // (but not too small) to ensure the OS doesn't try to adjust them.
863 const gfx::Rect kTestBounds(150, 150, 400, 300);
864 const gfx::Size kTestSize(200, 180);
866 // First test a toplevel widget.
867 Widget* widget = CreateTopLevelPlatformWidget();
870 EXPECT_NE(kTestSize.ToString(),
871 widget->GetWindowBoundsInScreen().size().ToString());
872 widget->SetSize(kTestSize);
873 EXPECT_EQ(kTestSize.ToString(),
874 widget->GetWindowBoundsInScreen().size().ToString());
876 EXPECT_NE(kTestBounds.ToString(),
877 widget->GetWindowBoundsInScreen().ToString());
878 widget->SetBounds(kTestBounds);
879 EXPECT_EQ(kTestBounds.ToString(),
880 widget->GetWindowBoundsInScreen().ToString());
882 // Changing just the size should not change the origin.
883 widget->SetSize(kTestSize);
884 EXPECT_EQ(kTestBounds.origin().ToString(),
885 widget->GetWindowBoundsInScreen().origin().ToString());
889 // Same tests with a frameless window.
890 widget = CreateTopLevelFramelessPlatformWidget();
893 EXPECT_NE(kTestSize.ToString(),
894 widget->GetWindowBoundsInScreen().size().ToString());
895 widget->SetSize(kTestSize);
896 EXPECT_EQ(kTestSize.ToString(),
897 widget->GetWindowBoundsInScreen().size().ToString());
899 EXPECT_NE(kTestBounds.ToString(),
900 widget->GetWindowBoundsInScreen().ToString());
901 widget->SetBounds(kTestBounds);
902 EXPECT_EQ(kTestBounds.ToString(),
903 widget->GetWindowBoundsInScreen().ToString());
905 // For a frameless widget, the client bounds should also match.
906 EXPECT_EQ(kTestBounds.ToString(),
907 widget->GetClientAreaBoundsInScreen().ToString());
909 // Verify origin is stable for a frameless window as well.
910 widget->SetSize(kTestSize);
911 EXPECT_EQ(kTestBounds.origin().ToString(),
912 widget->GetWindowBoundsInScreen().origin().ToString());
917 // Before being enabled on Mac, this was #ifdef(false).
918 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
919 #if defined(OS_MACOSX)
920 // Aura needs shell to maximize/fullscreen window.
921 // NativeWidgetGtk doesn't implement GetRestoredBounds.
922 TEST_F(WidgetTest, GetRestoredBounds) {
923 Widget* toplevel = CreateTopLevelPlatformWidget();
924 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
925 toplevel->GetRestoredBounds().ToString());
927 toplevel->Maximize();
928 RunPendingMessages();
929 #if defined(OS_MACOSX)
930 // Current expectation on Mac is to do nothing on Maximize.
931 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
932 toplevel->GetRestoredBounds().ToString());
934 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
935 toplevel->GetRestoredBounds().ToString());
937 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
938 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
941 RunPendingMessages();
942 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
943 toplevel->GetRestoredBounds().ToString());
945 toplevel->SetFullscreen(true);
946 RunPendingMessages();
947 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
948 toplevel->GetRestoredBounds().ToString());
949 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
950 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
954 // Test that window state is not changed after getting out of full screen.
955 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
956 Widget* toplevel = CreateTopLevelPlatformWidget();
959 RunPendingMessages();
961 // This should be a normal state window.
962 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
964 toplevel->SetFullscreen(true);
965 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
966 toplevel->SetFullscreen(false);
967 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
969 // And it should still be in normal state after getting out of full screen.
970 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
972 // On Mac, a "maximized" state is indistinguishable from a window that just
973 // fills the screen, so nothing to check there.
974 #if !defined(OS_MACOSX)
975 // Now, make it maximized.
976 toplevel->Maximize();
977 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
979 toplevel->SetFullscreen(true);
980 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
981 toplevel->SetFullscreen(false);
982 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
984 // And it stays maximized after getting out of full screen.
985 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
990 RunPendingMessages();
993 // The key-event propagation from Widget happens differently on aura and
994 // non-aura systems because of the difference in IME. So this test works only on
996 TEST_F(WidgetTest, KeyboardInputEvent) {
997 Widget* toplevel = CreateTopLevelPlatformWidget();
998 View* container = toplevel->client_view();
1000 Textfield* textfield = new Textfield();
1001 textfield->SetText(base::ASCIIToUTF16("some text"));
1002 container->AddChildView(textfield);
1004 textfield->RequestFocus();
1006 // The press gets handled. The release doesn't have an effect.
1007 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1008 toplevel->OnKeyEvent(&backspace_p);
1009 EXPECT_TRUE(backspace_p.stopped_propagation());
1010 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1011 toplevel->OnKeyEvent(&backspace_r);
1012 EXPECT_FALSE(backspace_r.handled());
1017 // Verifies bubbles result in a focus lost when shown.
1018 // TODO(msw): this tests relies on focus, it needs to be in
1019 // interactive_ui_tests.
1020 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1021 // Create a widget, show and activate it and focus the contents view.
1022 View* contents_view = new View;
1023 contents_view->SetFocusable(true);
1025 Widget::InitParams init_params =
1026 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1027 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1028 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1029 #if !defined(OS_CHROMEOS)
1030 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1032 widget.Init(init_params);
1033 widget.SetContentsView(contents_view);
1036 contents_view->RequestFocus();
1037 EXPECT_TRUE(contents_view->HasFocus());
1040 BubbleDelegateView* bubble_delegate_view =
1041 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1042 bubble_delegate_view->SetFocusable(true);
1043 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1044 bubble_delegate_view->RequestFocus();
1046 // |contents_view_| should no longer have focus.
1047 EXPECT_FALSE(contents_view->HasFocus());
1048 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1050 bubble_delegate_view->GetWidget()->CloseNow();
1052 // Closing the bubble should result in focus going back to the contents view.
1053 EXPECT_TRUE(contents_view->HasFocus());
1056 class TestBubbleDelegateView : public BubbleDelegateView {
1058 TestBubbleDelegateView(View* anchor)
1059 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1060 reset_controls_called_(false) {}
1061 ~TestBubbleDelegateView() override {}
1063 bool ShouldShowCloseButton() const override {
1064 reset_controls_called_ = true;
1068 mutable bool reset_controls_called_;
1071 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1072 Widget* anchor = CreateTopLevelPlatformWidget();
1075 TestBubbleDelegateView* bubble_delegate =
1076 new TestBubbleDelegateView(anchor->client_view());
1077 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1078 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1079 bubble_widget->Show();
1080 bubble_widget->CloseNow();
1086 // Desktop native widget Aura tests are for non Chrome OS platforms.
1087 #if !defined(OS_CHROMEOS)
1088 // Test to ensure that after minimize, view width is set to zero.
1089 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1092 Widget::InitParams init_params =
1093 CreateParams(Widget::InitParams::TYPE_WINDOW);
1094 init_params.show_state = ui::SHOW_STATE_NORMAL;
1095 gfx::Rect initial_bounds(0, 0, 300, 400);
1096 init_params.bounds = initial_bounds;
1097 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1098 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1099 widget.Init(init_params);
1100 NonClientView* non_client_view = widget.non_client_view();
1101 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1102 non_client_view->SetFrameView(frame_view);
1105 EXPECT_EQ(0, frame_view->width());
1108 // This class validates whether paints are received for a visible Widget.
1109 // To achieve this it overrides the Show and Close methods on the Widget class
1110 // and sets state whether subsequent paints are expected.
1111 class DesktopAuraTestValidPaintWidget : public views::Widget {
1113 DesktopAuraTestValidPaintWidget()
1114 : received_paint_(false),
1115 expect_paint_(true),
1116 received_paint_while_hidden_(false) {}
1118 ~DesktopAuraTestValidPaintWidget() override {}
1120 void InitForTest(Widget::InitParams create_params);
1122 void Show() override {
1123 expect_paint_ = true;
1124 views::Widget::Show();
1127 void Close() override {
1128 expect_paint_ = false;
1129 views::Widget::Close();
1133 expect_paint_ = false;
1134 views::Widget::Hide();
1137 void OnNativeWidgetPaint(gfx::Canvas* canvas) override {
1138 received_paint_ = true;
1139 EXPECT_TRUE(expect_paint_);
1141 received_paint_while_hidden_ = true;
1142 views::Widget::OnNativeWidgetPaint(canvas);
1145 bool ReadReceivedPaintAndReset() {
1146 bool result = received_paint_;
1147 received_paint_ = false;
1151 bool received_paint_while_hidden() const {
1152 return received_paint_while_hidden_;
1156 bool received_paint_;
1158 bool received_paint_while_hidden_;
1160 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1163 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1164 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1165 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1166 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1169 View* contents_view = new View;
1170 contents_view->SetFocusable(true);
1171 SetContentsView(contents_view);
1177 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1178 DesktopAuraTestValidPaintWidget widget;
1179 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1180 RunPendingMessages();
1181 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1182 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1184 RunPendingMessages();
1185 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1186 EXPECT_FALSE(widget.received_paint_while_hidden());
1189 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1190 DesktopAuraTestValidPaintWidget widget;
1191 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1192 RunPendingMessages();
1193 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1194 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1196 RunPendingMessages();
1197 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1198 EXPECT_FALSE(widget.received_paint_while_hidden());
1202 // Test to ensure that the aura Window's visiblity state is set to visible if
1203 // the underlying widget is hidden and then shown.
1204 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1207 Widget::InitParams init_params =
1208 CreateParams(Widget::InitParams::TYPE_WINDOW);
1209 init_params.show_state = ui::SHOW_STATE_NORMAL;
1210 gfx::Rect initial_bounds(0, 0, 300, 400);
1211 init_params.bounds = initial_bounds;
1212 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1213 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1214 widget.Init(init_params);
1215 NonClientView* non_client_view = widget.non_client_view();
1216 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1217 non_client_view->SetFrameView(frame_view);
1220 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1222 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1224 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1227 // The following code verifies we can correctly destroy a Widget from a mouse
1228 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1229 // nested message loops from such events, nor has the code ever really dealt
1230 // with this situation.
1232 // Generates two moves (first generates enter, second real move), a press, drag
1233 // and release stopping at |last_event_type|.
1234 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1235 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1236 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1237 screen_bounds.CenterPoint(), 0, 0);
1238 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1239 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1240 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1242 details = dispatcher->OnEventFromSource(&move_event);
1243 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1246 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1247 screen_bounds.CenterPoint(), 0, 0);
1248 details = dispatcher->OnEventFromSource(&press_event);
1249 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1252 gfx::Point end_point(screen_bounds.CenterPoint());
1253 end_point.Offset(1, 1);
1254 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1255 details = dispatcher->OnEventFromSource(&drag_event);
1256 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1259 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1261 details = dispatcher->OnEventFromSource(&release_event);
1262 if (details.dispatcher_destroyed)
1266 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1267 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1268 ui::EventType last_event_type) {
1269 // |widget| is deleted by CloseWidgetView.
1270 Widget* widget = new Widget;
1271 Widget::InitParams params =
1272 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1273 params.native_widget = new PlatformDesktopNativeWidget(widget);
1274 params.bounds = gfx::Rect(0, 0, 50, 100);
1275 widget->Init(params);
1276 widget->SetContentsView(new CloseWidgetView(last_event_type));
1278 GenerateMouseEvents(widget, last_event_type);
1281 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1282 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1283 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1286 // Verifies deleting the widget from a mouse released event doesn't crash.
1287 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1288 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1291 #endif // !defined(OS_CHROMEOS)
1293 // Tests that wheel events generated from scroll events are targetted to the
1294 // views under the cursor when the focused view does not processed them.
1295 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1296 EventCountView* cursor_view = new EventCountView;
1297 cursor_view->SetBounds(60, 0, 50, 40);
1299 Widget* widget = CreateTopLevelPlatformWidget();
1300 widget->GetRootView()->AddChildView(cursor_view);
1302 // Generate a scroll event on the cursor view.
1303 ui::ScrollEvent scroll(ui::ET_SCROLL,
1305 ui::EventTimeForNow(),
1310 widget->OnScrollEvent(&scroll);
1312 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1313 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1315 cursor_view->ResetCounts();
1317 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1319 ui::EventTimeForNow(),
1324 widget->OnScrollEvent(&scroll2);
1326 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1327 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1332 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1333 // events are not dispatched to any view.
1334 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1335 EventCountView* noscroll_view = new EventCountView;
1336 EventCountView* scroll_view = new ScrollableEventCountView;
1338 noscroll_view->SetBounds(0, 0, 50, 40);
1339 scroll_view->SetBounds(60, 0, 40, 40);
1341 Widget* widget = CreateTopLevelPlatformWidget();
1342 widget->GetRootView()->AddChildView(noscroll_view);
1343 widget->GetRootView()->AddChildView(scroll_view);
1346 ui::GestureEvent begin(
1351 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1352 widget->OnGestureEvent(&begin);
1353 ui::GestureEvent update(
1358 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1359 widget->OnGestureEvent(&update);
1360 ui::GestureEvent end(25,
1364 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1365 widget->OnGestureEvent(&end);
1367 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1368 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1369 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1373 ui::GestureEvent begin(
1378 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1379 widget->OnGestureEvent(&begin);
1380 ui::GestureEvent update(
1385 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1386 widget->OnGestureEvent(&update);
1387 ui::GestureEvent end(85,
1391 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1392 widget->OnGestureEvent(&end);
1394 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1395 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1396 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1402 // Tests that event-handlers installed on the RootView get triggered correctly.
1403 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1404 TEST_F(WidgetTest, EventHandlersOnRootView) {
1405 Widget* widget = CreateTopLevelNativeWidget();
1406 View* root_view = widget->GetRootView();
1408 scoped_ptr<EventCountView> view(new EventCountView());
1409 view->set_owned_by_client();
1410 view->SetBounds(0, 0, 20, 20);
1411 root_view->AddChildView(view.get());
1413 EventCountHandler h1;
1414 root_view->AddPreTargetHandler(&h1);
1416 EventCountHandler h2;
1417 root_view->AddPostTargetHandler(&h2);
1419 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1422 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1423 // bubble up the views hierarchy to be re-dispatched on the root view.
1424 ui::ScrollEvent scroll(ui::ET_SCROLL,
1426 ui::EventTimeForNow(),
1431 widget->OnScrollEvent(&scroll);
1432 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1433 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1434 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1436 // Unhandled scroll events are turned into wheel events and re-dispatched.
1437 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1438 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1439 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1442 view->ResetCounts();
1445 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1446 // should bubble up the views hierarchy to be re-dispatched on the root view.
1447 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1449 ui::EventTimeForNow(),
1454 widget->OnScrollEvent(&fling);
1455 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1456 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1457 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1459 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1460 // be turned into wheel events and re-dispatched.
1461 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1462 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1463 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1466 view->ResetCounts();
1469 // Change the handle mode of |view| so that events are marked as handled at
1470 // the target phase.
1471 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1473 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1474 // The events are handled at the target phase and should not reach the
1475 // post-target handler.
1476 ui::GestureEvent tap_down(5,
1479 ui::EventTimeForNow(),
1480 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1481 widget->OnGestureEvent(&tap_down);
1482 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1483 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1484 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1486 ui::GestureEvent tap_cancel(
1490 ui::EventTimeForNow(),
1491 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1492 widget->OnGestureEvent(&tap_cancel);
1493 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1494 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1495 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1498 view->ResetCounts();
1501 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1502 // and should not reach the post-target handler.
1503 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1505 ui::EventTimeForNow(),
1510 widget->OnScrollEvent(&consumed_scroll);
1511 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1512 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1513 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1515 // Handled scroll events are not turned into wheel events and re-dispatched.
1516 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1517 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1518 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1523 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1524 Widget* widget = CreateTopLevelNativeWidget();
1525 View* root_view = widget->GetRootView();
1527 EventCountView* v1 = new EventCountView();
1528 v1->SetBounds(0, 0, 10, 10);
1529 root_view->AddChildView(v1);
1530 EventCountView* v2 = new EventCountView();
1531 v2->SetBounds(0, 10, 10, 10);
1532 root_view->AddChildView(v2);
1534 gfx::Point cursor_location(5, 5);
1535 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1536 ui::EF_NONE, ui::EF_NONE);
1537 widget->OnMouseEvent(&move);
1539 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1540 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1543 v2->SetBounds(0, 0, 10, 10);
1544 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1546 widget->SynthesizeMouseMoveEvent();
1547 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1552 // ui::EventHandler which handles all mouse press events.
1553 class MousePressEventConsumer : public ui::EventHandler {
1555 explicit MousePressEventConsumer() {
1558 ~MousePressEventConsumer() override {}
1561 // ui::EventHandler:
1562 void OnMouseEvent(ui::MouseEvent* event) override {
1563 if (event->type() == ui::ET_MOUSE_PRESSED)
1564 event->SetHandled();
1567 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1572 // Test that mouse presses and mouse releases are dispatched normally when a
1574 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1575 Widget* widget = CreateTopLevelNativeWidget();
1577 widget->SetSize(gfx::Size(300, 300));
1579 EventCountView* event_count_view = new EventCountView();
1580 event_count_view->SetBounds(0, 0, 300, 300);
1581 widget->GetRootView()->AddChildView(event_count_view);
1583 MousePressEventConsumer consumer;
1584 event_count_view->AddPostTargetHandler(&consumer);
1586 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1587 generator.PressTouch();
1588 generator.ClickLeftButton();
1590 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1591 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1596 // Used by SingleWindowClosing to count number of times WindowClosing() has
1598 class ClosingDelegate : public WidgetDelegate {
1600 ClosingDelegate() : count_(0), widget_(NULL) {}
1602 int count() const { return count_; }
1604 void set_widget(views::Widget* widget) { widget_ = widget; }
1606 // WidgetDelegate overrides:
1607 Widget* GetWidget() override { return widget_; }
1608 const Widget* GetWidget() const override { return widget_; }
1609 void WindowClosing() override { count_++; }
1613 views::Widget* widget_;
1615 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1618 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1620 TEST_F(WidgetTest, SingleWindowClosing) {
1621 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1622 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1623 Widget::InitParams init_params =
1624 CreateParams(Widget::InitParams::TYPE_WINDOW);
1625 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1626 init_params.delegate = delegate.get();
1627 #if !defined(OS_CHROMEOS)
1628 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1630 widget->Init(init_params);
1631 EXPECT_EQ(0, delegate->count());
1633 EXPECT_EQ(1, delegate->count());
1636 class WidgetWindowTitleTest : public WidgetTest {
1638 void RunTest(bool desktop_native_widget) {
1639 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1640 Widget::InitParams init_params =
1641 CreateParams(Widget::InitParams::TYPE_WINDOW);
1642 widget->Init(init_params);
1644 #if !defined(OS_CHROMEOS)
1645 if (desktop_native_widget)
1646 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1648 DCHECK(!desktop_native_widget)
1649 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1652 internal::NativeWidgetPrivate* native_widget =
1653 widget->native_widget_private();
1655 base::string16 empty;
1656 base::string16 s1(base::UTF8ToUTF16("Title1"));
1657 base::string16 s2(base::UTF8ToUTF16("Title2"));
1658 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1660 // The widget starts with no title, setting empty should not change
1662 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1663 // Setting the title to something non-empty should cause a change.
1664 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1665 // Setting the title to something else with the same length should cause a
1667 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1668 // Setting the title to something else with a different length should cause
1670 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1671 // Setting the title to the same thing twice should not cause a change.
1672 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1678 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1679 // Use the default NativeWidget.
1680 bool desktop_native_widget = false;
1681 RunTest(desktop_native_widget);
1684 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1685 #if !defined(OS_CHROMEOS)
1686 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1687 // Override to use a DesktopNativeWidget.
1688 bool desktop_native_widget = true;
1689 RunTest(desktop_native_widget);
1691 #endif // !OS_CHROMEOS
1693 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1694 Widget* widget = new Widget;
1695 Widget::InitParams params =
1696 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1697 widget->Init(params);
1699 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1701 widget->SetSize(gfx::Size(100, 100));
1704 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1706 WidgetDeletionObserver deletion_observer(widget);
1707 generator.ClickLeftButton();
1708 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1710 // Yay we did not crash!
1713 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1714 Widget* widget = new Widget;
1715 Widget::InitParams params =
1716 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1717 widget->Init(params);
1719 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1721 widget->SetSize(gfx::Size(100, 100));
1724 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1726 WidgetDeletionObserver deletion_observer(widget);
1727 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1728 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1730 // Yay we did not crash!
1733 // See description of RunGetNativeThemeFromDestructor() for details.
1734 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1736 GetNativeThemeFromDestructorView() {}
1737 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1739 View* GetContentsView() override { return this; }
1742 void VerifyNativeTheme() {
1743 ASSERT_TRUE(GetNativeTheme() != NULL);
1746 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1749 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1750 // crash. |is_first_run| is true if this is the first call. A return value of
1751 // true indicates this should be run again with a value of false.
1752 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1753 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1754 bool is_first_run) {
1755 bool needs_second_run = false;
1756 // Destroyed by CloseNow() below.
1757 Widget* widget = new Widget;
1758 Widget::InitParams params(in_params);
1759 // Deletes itself when the Widget is destroyed.
1760 params.delegate = new GetNativeThemeFromDestructorView;
1761 #if !defined(OS_CHROMEOS)
1763 params.native_widget = new PlatformDesktopNativeWidget(widget);
1764 needs_second_run = true;
1767 widget->Init(params);
1769 return needs_second_run;
1772 // See description of RunGetNativeThemeFromDestructor() for details.
1773 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1774 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1775 if (RunGetNativeThemeFromDestructor(params, true))
1776 RunGetNativeThemeFromDestructor(params, false);
1779 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1781 class CloseDestroysWidget : public Widget {
1783 explicit CloseDestroysWidget(bool* destroyed)
1784 : destroyed_(destroyed) {
1787 ~CloseDestroysWidget() override {
1790 base::MessageLoop::current()->QuitNow();
1794 void Detach() { destroyed_ = NULL; }
1797 // If non-null set to true from destructor.
1800 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1803 // An observer that registers that an animation has ended.
1804 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1806 AnimationEndObserver() : animation_completed_(false) {}
1807 ~AnimationEndObserver() override {}
1809 bool animation_completed() const { return animation_completed_; }
1811 // ui::ImplicitAnimationObserver:
1812 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
1815 bool animation_completed_;
1817 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1820 // An observer that registers the bounds of a widget on destruction.
1821 class WidgetBoundsObserver : public WidgetObserver {
1823 WidgetBoundsObserver() {}
1824 ~WidgetBoundsObserver() override {}
1826 gfx::Rect bounds() { return bounds_; }
1829 void OnWidgetDestroying(Widget* widget) override {
1830 bounds_ = widget->GetWindowBoundsInScreen();
1836 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1839 // Verifies Close() results in destroying.
1840 TEST_F(WidgetTest, CloseDestroys) {
1841 bool destroyed = false;
1842 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1843 Widget::InitParams params =
1844 CreateParams(views::Widget::InitParams::TYPE_MENU);
1845 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1846 #if !defined(OS_CHROMEOS)
1847 params.native_widget = new PlatformDesktopNativeWidget(widget);
1849 widget->Init(params);
1853 EXPECT_FALSE(destroyed);
1854 // Run the message loop as Close() asynchronously deletes.
1855 base::RunLoop().Run();
1856 EXPECT_TRUE(destroyed);
1857 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1864 // Tests that killing a widget while animating it does not crash.
1865 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1866 scoped_ptr<Widget> widget(new Widget);
1867 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1868 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1869 params.bounds = gfx::Rect(50, 50, 250, 250);
1870 widget->Init(params);
1871 AnimationEndObserver animation_observer;
1872 WidgetBoundsObserver widget_observer;
1873 gfx::Rect bounds(0, 0, 50, 50);
1875 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1876 // animating the movement.
1877 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1878 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1879 ui::ScopedLayerAnimationSettings animation_settings(
1880 widget->GetLayer()->GetAnimator());
1881 animation_settings.AddObserver(&animation_observer);
1882 widget->AddObserver(&widget_observer);
1885 // Animate the bounds change.
1886 widget->SetBounds(bounds);
1888 EXPECT_FALSE(animation_observer.animation_completed());
1890 EXPECT_TRUE(animation_observer.animation_completed());
1891 EXPECT_EQ(widget_observer.bounds(), bounds);
1894 // A view that consumes mouse-pressed event and gesture-tap-down events.
1895 class RootViewTestView : public View {
1897 RootViewTestView(): View() {}
1900 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
1902 void OnGestureEvent(ui::GestureEvent* event) override {
1903 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1904 event->SetHandled();
1908 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1909 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1911 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1912 DISABLED_TestRootViewHandlersWhenHidden
1914 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1915 TestRootViewHandlersWhenHidden
1917 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1918 Widget* widget = CreateTopLevelNativeWidget();
1919 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1920 View* view = new RootViewTestView();
1921 view->SetBounds(0, 0, 300, 300);
1922 internal::RootView* root_view =
1923 static_cast<internal::RootView*>(widget->GetRootView());
1924 root_view->AddChildView(view);
1926 // Check RootView::mouse_pressed_handler_.
1928 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1929 gfx::Point click_location(45, 15);
1930 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1931 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1932 widget->OnMouseEvent(&press);
1933 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1935 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1937 // Check RootView::mouse_move_handler_.
1939 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1940 gfx::Point move_location(45, 15);
1941 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1942 widget->OnMouseEvent(&move);
1943 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1945 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1947 // Check RootView::gesture_handler_.
1949 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1950 ui::GestureEvent tap_down(15,
1954 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1955 widget->OnGestureEvent(&tap_down);
1956 EXPECT_EQ(view, GetGestureHandler(root_view));
1958 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1963 // Convenience to make constructing a GestureEvent simpler.
1964 class GestureEventForTest : public ui::GestureEvent {
1966 GestureEventForTest(ui::EventType type, int x, int y)
1971 ui::GestureEventDetails(type)) {}
1973 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
1974 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
1977 // Tests that the |gesture_handler_| member in RootView is always NULL
1978 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
1979 // the release of the final touch point on the screen, but that
1980 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
1981 // point do not modify |gesture_handler_|.
1982 TEST_F(WidgetTest, GestureEndEvents) {
1983 Widget* widget = CreateTopLevelNativeWidget();
1984 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1985 EventCountView* view = new EventCountView();
1986 view->SetBounds(0, 0, 300, 300);
1987 internal::RootView* root_view =
1988 static_cast<internal::RootView*>(widget->GetRootView());
1989 root_view->AddChildView(view);
1992 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
1993 // the gesture handler.
1994 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1995 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
1996 widget->OnGestureEvent(&end);
1997 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1999 // Change the handle mode of |view| to indicate that it would like
2000 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2001 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2002 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2003 widget->OnGestureEvent(&tap);
2004 EXPECT_TRUE(tap.handled());
2005 EXPECT_EQ(view, GetGestureHandler(root_view));
2007 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2008 // corresponding to a second touch point, but should be reset to NULL by a
2009 // ui::ET_GESTURE_END corresponding to the final touch point.
2010 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2011 details.set_touch_points(2);
2012 GestureEventForTest end_second_touch_point(details, 15, 15);
2013 widget->OnGestureEvent(&end_second_touch_point);
2014 EXPECT_EQ(view, GetGestureHandler(root_view));
2016 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2017 widget->OnGestureEvent(&end);
2018 EXPECT_TRUE(end.handled());
2019 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2021 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2022 // mode of |view| to indicate that it does not want to handle any
2024 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2025 widget->OnGestureEvent(&tap);
2026 EXPECT_TRUE(tap.handled());
2027 EXPECT_EQ(view, GetGestureHandler(root_view));
2028 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2030 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2031 // corresponding to a second touch point, but should be reset to NULL by a
2032 // ui::ET_GESTURE_END corresponding to the final touch point.
2033 end_second_touch_point = GestureEventForTest(details, 15, 15);
2034 widget->OnGestureEvent(&end_second_touch_point);
2035 EXPECT_EQ(view, GetGestureHandler(root_view));
2037 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2038 widget->OnGestureEvent(&end);
2039 EXPECT_FALSE(end.handled());
2040 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2045 // Tests that gesture events which should not be processed (because
2046 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2047 // dispatched to any views.
2048 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2049 Widget* widget = CreateTopLevelNativeWidget();
2050 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2052 // Define a hierarchy of four views (coordinates are in
2053 // their parent coordinate space).
2054 // v1 (0, 0, 300, 300)
2055 // v2 (0, 0, 100, 100)
2056 // v3 (0, 0, 50, 50)
2058 EventCountView* v1 = new EventCountView();
2059 v1->SetBounds(0, 0, 300, 300);
2060 EventCountView* v2 = new EventCountView();
2061 v2->SetBounds(0, 0, 100, 100);
2062 EventCountView* v3 = new EventCountView();
2063 v3->SetBounds(0, 0, 50, 50);
2064 EventCountView* v4 = new EventCountView();
2065 v4->SetBounds(0, 0, 10, 10);
2066 internal::RootView* root_view =
2067 static_cast<internal::RootView*>(widget->GetRootView());
2068 root_view->AddChildView(v1);
2069 v1->AddChildView(v2);
2070 v2->AddChildView(v3);
2071 v3->AddChildView(v4);
2075 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2076 // they should be marked as handled by OnEventProcessingStarted().
2077 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2078 widget->OnGestureEvent(&begin);
2079 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2080 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2081 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2082 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2083 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2084 EXPECT_TRUE(begin.handled());
2090 // ui::ET_GESTURE_END events should not be seen by any view when there is
2091 // no default gesture handler set, but they should be marked as handled by
2092 // OnEventProcessingStarted().
2093 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2094 widget->OnGestureEvent(&end);
2095 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2096 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2097 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2098 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2099 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2100 EXPECT_TRUE(end.handled());
2106 // ui::ET_GESTURE_END events not corresponding to the release of the
2107 // final touch point should never be seen by any view, but they should
2108 // be marked as handled by OnEventProcessingStarted().
2109 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2110 details.set_touch_points(2);
2111 GestureEventForTest end_second_touch_point(details, 5, 5);
2112 widget->OnGestureEvent(&end_second_touch_point);
2113 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2114 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2115 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2116 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2117 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2118 EXPECT_TRUE(end_second_touch_point.handled());
2124 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2125 // there is no default gesture handler set, but they should be marked as
2126 // handled by OnEventProcessingStarted().
2127 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2128 widget->OnGestureEvent(&scroll_update);
2129 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2130 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2131 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2132 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2133 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2134 EXPECT_TRUE(scroll_update.handled());
2140 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2141 // there is no default gesture handler set, but they should be marked as
2142 // handled by OnEventProcessingStarted().
2143 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2144 widget->OnGestureEvent(&scroll_end);
2145 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2146 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2147 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2148 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2149 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2150 EXPECT_TRUE(scroll_end.handled());
2156 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2157 // there is no default gesture handler set, but they should be marked as
2158 // handled by OnEventProcessingStarted().
2159 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2160 widget->OnGestureEvent(&scroll_fling_start);
2161 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2162 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2163 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2164 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2165 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2166 EXPECT_TRUE(scroll_fling_start.handled());
2175 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2176 // in a view hierarchy and that the default gesture handler in RootView is set
2178 TEST_F(WidgetTest, GestureEventDispatch) {
2179 Widget* widget = CreateTopLevelNativeWidget();
2180 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2182 // Define a hierarchy of four views (coordinates are in
2183 // their parent coordinate space).
2184 // v1 (0, 0, 300, 300)
2185 // v2 (0, 0, 100, 100)
2186 // v3 (0, 0, 50, 50)
2188 EventCountView* v1 = new EventCountView();
2189 v1->SetBounds(0, 0, 300, 300);
2190 EventCountView* v2 = new EventCountView();
2191 v2->SetBounds(0, 0, 100, 100);
2192 EventCountView* v3 = new EventCountView();
2193 v3->SetBounds(0, 0, 50, 50);
2194 EventCountView* v4 = new EventCountView();
2195 v4->SetBounds(0, 0, 10, 10);
2196 internal::RootView* root_view =
2197 static_cast<internal::RootView*>(widget->GetRootView());
2198 root_view->AddChildView(v1);
2199 v1->AddChildView(v2);
2200 v2->AddChildView(v3);
2201 v3->AddChildView(v4);
2205 // No gesture handler is set in the root view and none of the views in the
2206 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2207 // event should be dispatched to all views in the hierarchy, the gesture
2208 // handler should remain unset, and the event should remain unhandled.
2209 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2210 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2211 widget->OnGestureEvent(&tap);
2212 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2213 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2214 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2215 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2216 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2217 EXPECT_FALSE(tap.handled());
2219 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2220 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2221 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2222 // and the event should be marked as handled.
2227 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2228 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2229 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2230 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2231 widget->OnGestureEvent(&tap);
2232 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2233 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2234 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2235 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2236 EXPECT_EQ(v3, GetGestureHandler(root_view));
2237 EXPECT_TRUE(tap.handled());
2239 // The gesture handler is set to |v3| and all views handle all gesture event
2240 // types. In this case subsequent gesture events should only be dispatched to
2241 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2246 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2247 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2248 widget->OnGestureEvent(&tap);
2249 EXPECT_TRUE(tap.handled());
2250 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2251 widget->OnGestureEvent(&show_press);
2252 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2253 widget->OnGestureEvent(&tap);
2254 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2255 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2256 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2257 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2258 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2259 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2260 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2261 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2262 EXPECT_TRUE(tap.handled());
2263 EXPECT_TRUE(show_press.handled());
2264 EXPECT_EQ(v3, GetGestureHandler(root_view));
2266 // The gesture handler is set to |v3|, but |v3| does not handle
2267 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2268 // only to |v3|, but the event should remain unhandled. The gesture handler
2269 // should remain as |v3|.
2274 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2275 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2276 widget->OnGestureEvent(&tap);
2277 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2278 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2279 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2280 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2281 EXPECT_FALSE(tap.handled());
2282 EXPECT_EQ(v3, GetGestureHandler(root_view));
2287 // Tests that gesture scroll events will change the default gesture handler in
2288 // RootView if the current handler to which they are dispatched does not handle
2289 // gesture scroll events.
2290 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2291 Widget* widget = CreateTopLevelNativeWidget();
2292 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2294 // Define a hierarchy of four views (coordinates are in
2295 // their parent coordinate space).
2296 // v1 (0, 0, 300, 300)
2297 // v2 (0, 0, 100, 100)
2298 // v3 (0, 0, 50, 50)
2300 EventCountView* v1 = new EventCountView();
2301 v1->SetBounds(0, 0, 300, 300);
2302 EventCountView* v2 = new EventCountView();
2303 v2->SetBounds(0, 0, 100, 100);
2304 EventCountView* v3 = new EventCountView();
2305 v3->SetBounds(0, 0, 50, 50);
2306 EventCountView* v4 = new EventCountView();
2307 v4->SetBounds(0, 0, 10, 10);
2308 internal::RootView* root_view =
2309 static_cast<internal::RootView*>(widget->GetRootView());
2310 root_view->AddChildView(v1);
2311 v1->AddChildView(v2);
2312 v2->AddChildView(v3);
2313 v3->AddChildView(v4);
2317 // Change the handle mode of |v3| to indicate that it would like to handle
2319 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2321 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2322 // should bubble up the views hierarchy until it reaches the first view
2323 // that will handle it (|v3|) and then sets the handler to |v3|.
2324 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2325 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2326 widget->OnGestureEvent(&tap_down);
2327 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2328 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2329 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2330 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2331 EXPECT_EQ(v3, GetGestureHandler(root_view));
2332 EXPECT_TRUE(tap_down.handled());
2338 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2339 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2340 widget->OnGestureEvent(&tap_cancel);
2341 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2342 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2343 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2344 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2345 EXPECT_EQ(v3, GetGestureHandler(root_view));
2346 EXPECT_TRUE(tap_cancel.handled());
2352 // Change the handle mode of |v3| to indicate that it would no longer like
2353 // to handle events, and change the mode of |v1| to indicate that it would
2354 // like to handle events.
2355 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2356 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2358 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2359 // handler (|v3|) does not handle scroll events, the event should bubble up
2360 // the views hierarchy until it reaches the first view that will handle
2361 // it (|v1|) and then sets the handler to |v1|.
2362 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2363 widget->OnGestureEvent(&scroll_begin);
2364 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2365 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2366 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2367 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2368 EXPECT_EQ(v1, GetGestureHandler(root_view));
2369 EXPECT_TRUE(scroll_begin.handled());
2375 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2377 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2378 widget->OnGestureEvent(&scroll_update);
2379 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2380 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2381 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2382 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2383 EXPECT_EQ(v1, GetGestureHandler(root_view));
2384 EXPECT_TRUE(scroll_update.handled());
2390 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2391 // directly and should not reset the gesture handler.
2392 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2393 widget->OnGestureEvent(&scroll_end);
2394 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2395 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2396 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2397 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2398 EXPECT_EQ(v1, GetGestureHandler(root_view));
2399 EXPECT_TRUE(scroll_end.handled());
2405 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2406 // still be dispatched to |v1| directly.
2407 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2408 widget->OnGestureEvent(&pinch_begin);
2409 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2410 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2411 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2412 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2413 EXPECT_EQ(v1, GetGestureHandler(root_view));
2414 EXPECT_TRUE(pinch_begin.handled());
2420 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2421 // set the gesture handler to NULL.
2422 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2423 widget->OnGestureEvent(&end);
2424 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2425 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2426 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2427 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2428 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2429 EXPECT_TRUE(end.handled());
2434 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2435 // that when a gesture event bubbles up a View hierarchy, the location
2436 // of a gesture event seen by each View is in the local coordinate space
2438 class GestureLocationView : public EventCountView {
2440 GestureLocationView() {}
2441 ~GestureLocationView() override {}
2443 void set_expected_location(gfx::Point expected_location) {
2444 expected_location_ = expected_location;
2448 void OnGestureEvent(ui::GestureEvent* event) override {
2449 EventCountView::OnGestureEvent(event);
2451 // Verify that the location of |event| is in the local coordinate
2453 EXPECT_EQ(expected_location_, event->location());
2457 // The expected location of a gesture event dispatched to |this|.
2458 gfx::Point expected_location_;
2460 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2463 // Verifies that the location of a gesture event is always in the local
2464 // coordinate space of the View receiving the event while bubbling.
2465 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2466 Widget* widget = CreateTopLevelNativeWidget();
2467 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2469 // Define a hierarchy of three views (coordinates shown below are in the
2470 // coordinate space of the root view, but the coordinates used for
2471 // SetBounds() are in their parent coordinate space).
2472 // v1 (50, 50, 150, 150)
2473 // v2 (100, 70, 50, 80)
2474 // v3 (120, 100, 10, 10)
2475 GestureLocationView* v1 = new GestureLocationView();
2476 v1->SetBounds(50, 50, 150, 150);
2477 GestureLocationView* v2 = new GestureLocationView();
2478 v2->SetBounds(50, 20, 50, 80);
2479 GestureLocationView* v3 = new GestureLocationView();
2480 v3->SetBounds(20, 30, 10, 10);
2481 internal::RootView* root_view =
2482 static_cast<internal::RootView*>(widget->GetRootView());
2483 root_view->AddChildView(v1);
2484 v1->AddChildView(v2);
2485 v2->AddChildView(v3);
2489 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2490 // This event is contained within all of |v1|, |v2|, and |v3|.
2491 gfx::Point location_in_root(125, 105);
2492 GestureEventForTest tap(
2493 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2495 // Calculate the location of the event in the local coordinate spaces
2496 // of each of the views.
2497 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2498 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2499 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2500 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2501 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2502 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2504 // Dispatch the event. When each view receives the event, its location should
2505 // be in the local coordinate space of that view (see the check made by
2506 // GestureLocationView). After dispatch is complete the event's location
2507 // should be in the root coordinate space.
2508 v1->set_expected_location(location_in_v1);
2509 v2->set_expected_location(location_in_v2);
2510 v3->set_expected_location(location_in_v3);
2511 widget->OnGestureEvent(&tap);
2512 EXPECT_EQ(location_in_root, tap.location());
2514 // Verify that each view did in fact see the event.
2515 EventCountView* view1 = v1;
2516 EventCountView* view2 = v2;
2517 EventCountView* view3 = v3;
2518 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2519 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2520 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2525 // Verifies that disabled views are permitted to be set as the default gesture
2526 // handler in RootView. Also verifies that gesture events targeted to a disabled
2527 // view are not actually dispatched to the view, but are still marked as
2529 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2530 Widget* widget = CreateTopLevelNativeWidget();
2531 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2533 // Define a hierarchy of four views (coordinates are in
2534 // their parent coordinate space).
2535 // v1 (0, 0, 300, 300)
2536 // v2 (0, 0, 100, 100)
2537 // v3 (0, 0, 50, 50)
2539 EventCountView* v1 = new EventCountView();
2540 v1->SetBounds(0, 0, 300, 300);
2541 EventCountView* v2 = new EventCountView();
2542 v2->SetBounds(0, 0, 100, 100);
2543 EventCountView* v3 = new EventCountView();
2544 v3->SetBounds(0, 0, 50, 50);
2545 EventCountView* v4 = new EventCountView();
2546 v4->SetBounds(0, 0, 10, 10);
2547 internal::RootView* root_view =
2548 static_cast<internal::RootView*>(widget->GetRootView());
2549 root_view->AddChildView(v1);
2550 v1->AddChildView(v2);
2551 v2->AddChildView(v3);
2552 v3->AddChildView(v4);
2556 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2558 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2559 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2560 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2561 v3->SetEnabled(false);
2563 // No gesture handler is set in the root view. In this case the tap event
2564 // should be dispatched only to |v4|, the gesture handler should be set to
2565 // |v3|, and the event should be marked as handled.
2566 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2567 widget->OnGestureEvent(&tap);
2568 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2569 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2570 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2571 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2572 EXPECT_EQ(v3, GetGestureHandler(root_view));
2573 EXPECT_TRUE(tap.handled());
2579 // A subsequent gesture event should be marked as handled but not dispatched.
2580 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2581 widget->OnGestureEvent(&tap);
2582 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2583 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2584 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2585 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2586 EXPECT_EQ(v3, GetGestureHandler(root_view));
2587 EXPECT_TRUE(tap.handled());
2593 // A GESTURE_END should reset the default gesture handler to NULL. It should
2594 // also not be dispatched to |v3| but still marked as handled.
2595 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2596 widget->OnGestureEvent(&end);
2597 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2598 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2599 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2600 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2601 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2602 EXPECT_TRUE(end.handled());
2608 // Change the handle mode of |v3| to indicate that it would no longer like
2609 // to handle events which are dispatched to it.
2610 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2612 // No gesture handler is set in the root view. In this case the tap event
2613 // should be dispatched only to |v4| and the event should be marked as
2614 // handled. Furthermore, the gesture handler should be set to
2615 // |v3|; even though |v3| does not explicitly handle events, it is a
2616 // valid target for the tap event because it is disabled.
2617 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2618 widget->OnGestureEvent(&tap);
2619 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2620 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2621 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2622 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2623 EXPECT_EQ(v3, GetGestureHandler(root_view));
2624 EXPECT_TRUE(tap.handled());
2630 // A GESTURE_END should reset the default gesture handler to NULL. It should
2631 // also not be dispatched to |v3| but still marked as handled.
2632 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2633 widget->OnGestureEvent(&end);
2634 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2635 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2636 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2637 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2638 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2639 EXPECT_TRUE(end.handled());
2644 // Test the result of Widget::GetAllChildWidgets().
2645 TEST_F(WidgetTest, GetAllChildWidgets) {
2646 // Create the following widget hierarchy:
2654 Widget* toplevel = CreateTopLevelPlatformWidget();
2655 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2656 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2657 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2658 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2659 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2661 std::set<Widget*> expected;
2662 expected.insert(toplevel);
2663 expected.insert(w1);
2664 expected.insert(w11);
2665 expected.insert(w2);
2666 expected.insert(w21);
2667 expected.insert(w22);
2669 std::set<Widget*> widgets;
2670 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2672 EXPECT_EQ(expected.size(), widgets.size());
2673 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2676 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2678 class DestroyedTrackingView : public View {
2680 DestroyedTrackingView(const std::string& name,
2681 std::vector<std::string>* add_to)
2686 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2689 const std::string name_;
2690 std::vector<std::string>* add_to_;
2692 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2695 class WidgetChildDestructionTest : public WidgetTest {
2697 WidgetChildDestructionTest() {}
2699 // Creates a top level and a child, destroys the child and verifies the views
2700 // of the child are destroyed before the views of the parent.
2701 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2702 bool child_has_desktop_native_widget_aura) {
2703 // When a View is destroyed its name is added here.
2704 std::vector<std::string> destroyed;
2706 Widget* top_level = new Widget;
2707 Widget::InitParams params =
2708 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2709 #if !defined(OS_CHROMEOS)
2710 if (top_level_has_desktop_native_widget_aura)
2711 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2713 top_level->Init(params);
2714 top_level->GetRootView()->AddChildView(
2715 new DestroyedTrackingView("parent", &destroyed));
2718 Widget* child = new Widget;
2719 Widget::InitParams child_params =
2720 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2721 child_params.parent = top_level->GetNativeView();
2722 #if !defined(OS_CHROMEOS)
2723 if (child_has_desktop_native_widget_aura)
2724 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2726 child->Init(child_params);
2727 child->GetRootView()->AddChildView(
2728 new DestroyedTrackingView("child", &destroyed));
2731 // Should trigger destruction of the child too.
2732 top_level->native_widget_private()->CloseNow();
2734 // Child should be destroyed first.
2735 ASSERT_EQ(2u, destroyed.size());
2736 EXPECT_EQ("child", destroyed[0]);
2737 EXPECT_EQ("parent", destroyed[1]);
2741 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2744 #if !defined(OS_CHROMEOS)
2745 // See description of RunDestroyChildWidgetsTest(). Parent uses
2746 // DesktopNativeWidgetAura.
2747 TEST_F(WidgetChildDestructionTest,
2748 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2749 RunDestroyChildWidgetsTest(true, false);
2752 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2753 // DesktopNativeWidgetAura.
2754 TEST_F(WidgetChildDestructionTest,
2755 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2756 RunDestroyChildWidgetsTest(true, true);
2758 #endif // !defined(OS_CHROMEOS)
2760 // See description of RunDestroyChildWidgetsTest().
2761 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2762 RunDestroyChildWidgetsTest(false, false);
2765 #if !defined(OS_CHROMEOS)
2766 // Provides functionality to create a window modal dialog.
2767 class ModalDialogDelegate : public DialogDelegateView {
2769 ModalDialogDelegate() {}
2770 ~ModalDialogDelegate() override {}
2772 // WidgetDelegate overrides.
2773 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
2776 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2779 // This test verifies that whether mouse events when a modal dialog is
2780 // displayed are eaten or recieved by the dialog.
2781 TEST_F(WidgetTest, WindowMouseModalityTest) {
2782 // Create a top level widget.
2783 Widget top_level_widget;
2784 Widget::InitParams init_params =
2785 CreateParams(Widget::InitParams::TYPE_WINDOW);
2786 init_params.show_state = ui::SHOW_STATE_NORMAL;
2787 gfx::Rect initial_bounds(0, 0, 500, 500);
2788 init_params.bounds = initial_bounds;
2789 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2790 init_params.native_widget =
2791 new PlatformDesktopNativeWidget(&top_level_widget);
2792 top_level_widget.Init(init_params);
2793 top_level_widget.Show();
2794 EXPECT_TRUE(top_level_widget.IsVisible());
2796 // Create a view and validate that a mouse moves makes it to the view.
2797 EventCountView* widget_view = new EventCountView();
2798 widget_view->SetBounds(0, 0, 10, 10);
2799 top_level_widget.GetRootView()->AddChildView(widget_view);
2801 gfx::Point cursor_location_main(5, 5);
2802 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2803 cursor_location_main,
2804 cursor_location_main,
2807 ui::EventDispatchDetails details =
2808 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2809 ASSERT_FALSE(details.dispatcher_destroyed);
2811 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2812 widget_view->ResetCounts();
2814 // Create a modal dialog and validate that a mouse down message makes it to
2815 // the main view within the dialog.
2817 // This instance will be destroyed when the dialog is destroyed.
2818 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2820 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2821 dialog_delegate, NULL, top_level_widget.GetNativeView());
2822 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2823 EventCountView* dialog_widget_view = new EventCountView();
2824 dialog_widget_view->SetBounds(0, 0, 50, 50);
2825 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2826 modal_dialog_widget->Show();
2827 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2829 gfx::Point cursor_location_dialog(100, 100);
2830 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2831 cursor_location_dialog,
2832 cursor_location_dialog,
2835 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2836 &mouse_down_dialog);
2837 ASSERT_FALSE(details.dispatcher_destroyed);
2838 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2840 // Send a mouse move message to the main window. It should not be received by
2841 // the main window as the modal dialog is still active.
2842 gfx::Point cursor_location_main2(6, 6);
2843 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2844 cursor_location_main2,
2845 cursor_location_main2,
2848 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2850 ASSERT_FALSE(details.dispatcher_destroyed);
2851 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2853 modal_dialog_widget->CloseNow();
2854 top_level_widget.CloseNow();
2857 // Verifies nativeview visbility matches that of Widget visibility when
2858 // SetFullscreen is invoked.
2859 TEST_F(WidgetTest, FullscreenStatePropagated) {
2860 Widget::InitParams init_params =
2861 CreateParams(Widget::InitParams::TYPE_WINDOW);
2862 init_params.show_state = ui::SHOW_STATE_NORMAL;
2863 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2864 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2867 Widget top_level_widget;
2868 top_level_widget.Init(init_params);
2869 top_level_widget.SetFullscreen(true);
2870 EXPECT_EQ(top_level_widget.IsVisible(),
2871 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2872 top_level_widget.CloseNow();
2874 #if !defined(OS_CHROMEOS)
2876 Widget top_level_widget;
2877 init_params.native_widget =
2878 new PlatformDesktopNativeWidget(&top_level_widget);
2879 top_level_widget.Init(init_params);
2880 top_level_widget.SetFullscreen(true);
2881 EXPECT_EQ(top_level_widget.IsVisible(),
2882 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2883 top_level_widget.CloseNow();
2889 // Provides functionality to test widget activation via an activation flag
2890 // which can be set by an accessor.
2891 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2893 ModalWindowTestWidgetDelegate()
2895 can_activate_(true) {}
2897 virtual ~ModalWindowTestWidgetDelegate() {}
2899 // Overridden from WidgetDelegate:
2900 virtual void DeleteDelegate() override {
2903 virtual Widget* GetWidget() override {
2906 virtual const Widget* GetWidget() const override {
2909 virtual bool CanActivate() const override {
2910 return can_activate_;
2912 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
2916 void set_can_activate(bool can_activate) {
2917 can_activate_ = can_activate;
2920 void set_widget(Widget* widget) {
2928 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2931 // Tests whether we can activate the top level widget when a modal dialog is
2933 TEST_F(WidgetTest, WindowModalityActivationTest) {
2934 // Destroyed when the top level widget created below is destroyed.
2935 ModalWindowTestWidgetDelegate* widget_delegate =
2936 new ModalWindowTestWidgetDelegate;
2937 // Create a top level widget.
2938 Widget top_level_widget;
2939 Widget::InitParams init_params =
2940 CreateParams(Widget::InitParams::TYPE_WINDOW);
2941 init_params.show_state = ui::SHOW_STATE_NORMAL;
2942 gfx::Rect initial_bounds(0, 0, 500, 500);
2943 init_params.bounds = initial_bounds;
2944 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2945 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2946 init_params.delegate = widget_delegate;
2947 top_level_widget.Init(init_params);
2948 widget_delegate->set_widget(&top_level_widget);
2949 top_level_widget.Show();
2950 EXPECT_TRUE(top_level_widget.IsVisible());
2952 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2953 EXPECT_TRUE(::IsWindow(win32_window));
2955 // This instance will be destroyed when the dialog is destroyed.
2956 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2958 // We should be able to activate the window even if the WidgetDelegate
2959 // says no, when a modal dialog is active.
2960 widget_delegate->set_can_activate(false);
2962 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2963 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2964 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2965 modal_dialog_widget->Show();
2966 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2968 LRESULT activate_result = ::SendMessage(
2971 reinterpret_cast<WPARAM>(win32_window),
2972 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2973 EXPECT_EQ(activate_result, MA_ACTIVATE);
2975 modal_dialog_widget->CloseNow();
2976 top_level_widget.CloseNow();
2978 #endif // defined(OS_WIN)
2979 #endif // !defined(OS_CHROMEOS)
2981 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2982 Widget* widget = CreateTopLevelPlatformWidget();
2985 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2990 // OSX does not have a per-application "active" window such as provided by
2991 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
2992 // is updated asynchronously.
2993 #if defined(OS_MACOSX)
2994 #define MAYBE_ShowInactive DISABLED_ShowInactive
2996 #define MAYBE_ShowInactive ShowInactive
2998 TEST_F(WidgetTest, MAYBE_ShowInactive) {
2999 Widget* widget = CreateTopLevelPlatformWidget();
3001 widget->ShowInactive();
3002 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
3007 TEST_F(WidgetTest, InactiveBeforeShow) {
3008 Widget* widget = CreateTopLevelPlatformWidget();
3010 EXPECT_FALSE(widget->IsActive());
3011 EXPECT_FALSE(widget->IsVisible());
3015 EXPECT_TRUE(widget->IsActive());
3016 EXPECT_TRUE(widget->IsVisible());
3021 TEST_F(WidgetTest, ShowInactiveAfterShow) {
3022 // Create 2 widgets to ensure window layering does not change.
3023 Widget* widget = CreateTopLevelPlatformWidget();
3024 Widget* widget2 = CreateTopLevelPlatformWidget();
3027 EXPECT_FALSE(widget->IsActive());
3028 EXPECT_TRUE(widget2->IsVisible());
3029 EXPECT_TRUE(widget2->IsActive());
3032 EXPECT_TRUE(widget->IsActive());
3033 EXPECT_FALSE(widget2->IsActive());
3034 widget->ShowInactive();
3035 EXPECT_TRUE(widget->IsActive());
3036 EXPECT_FALSE(widget2->IsActive());
3037 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3039 widget2->CloseNow();
3043 TEST_F(WidgetTest, ShowAfterShowInactive) {
3044 Widget* widget = CreateTopLevelPlatformWidget();
3046 widget->ShowInactive();
3048 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3053 #if !defined(OS_CHROMEOS)
3054 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
3055 Widget* widget = CreateTopLevelPlatformWidget();
3057 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3060 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3061 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
3062 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3063 widget2.Init(params);
3066 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
3067 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3072 #endif // !defined(OS_CHROMEOS)
3076 class FullscreenAwareFrame : public views::NonClientFrameView {
3078 explicit FullscreenAwareFrame(views::Widget* widget)
3079 : widget_(widget), fullscreen_layout_called_(false) {}
3080 ~FullscreenAwareFrame() override {}
3082 // views::NonClientFrameView overrides:
3083 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3084 gfx::Rect GetWindowBoundsForClientBounds(
3085 const gfx::Rect& client_bounds) const override {
3088 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3089 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3090 void ResetWindowControls() override {}
3091 void UpdateWindowIcon() override {}
3092 void UpdateWindowTitle() override {}
3093 void SizeConstraintsChanged() override {}
3095 // views::View overrides:
3096 void Layout() override {
3097 if (widget_->IsFullscreen())
3098 fullscreen_layout_called_ = true;
3101 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3104 views::Widget* widget_;
3105 bool fullscreen_layout_called_;
3107 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3112 // Tests that frame Layout is called when a widget goes fullscreen without
3113 // changing its size or title.
3114 TEST_F(WidgetTest, FullscreenFrameLayout) {
3115 Widget* widget = CreateTopLevelPlatformWidget();
3116 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3117 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3120 RunPendingMessages();
3122 EXPECT_FALSE(frame->fullscreen_layout_called());
3123 widget->SetFullscreen(true);
3125 RunPendingMessages();
3126 EXPECT_TRUE(frame->fullscreen_layout_called());
3131 #if !defined(OS_CHROMEOS)
3134 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3135 // OnWindowDestroying.
3136 class IsActiveFromDestroyObserver : public WidgetObserver {
3138 IsActiveFromDestroyObserver() {}
3139 ~IsActiveFromDestroyObserver() override {}
3140 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3143 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3148 // Verifies Widget::IsActive() invoked from
3149 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3150 TEST_F(WidgetTest, IsActiveFromDestroy) {
3151 // Create two widgets, one a child of the other.
3152 IsActiveFromDestroyObserver observer;
3153 Widget parent_widget;
3154 Widget::InitParams parent_params =
3155 CreateParams(Widget::InitParams::TYPE_POPUP);
3156 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3157 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3158 parent_widget.Init(parent_params);
3159 parent_widget.Show();
3161 Widget child_widget;
3162 Widget::InitParams child_params =
3163 CreateParams(Widget::InitParams::TYPE_POPUP);
3164 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3165 child_params.context = parent_widget.GetNativeWindow();
3166 child_widget.Init(child_params);
3167 child_widget.AddObserver(&observer);
3168 child_widget.Show();
3170 parent_widget.CloseNow();
3172 #endif // !defined(OS_CHROMEOS)
3174 // Tests that events propagate through from the dispatcher with the correct
3175 // event type, and that the different platforms behave the same.
3176 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3177 EventCountView* view = new EventCountView;
3178 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3179 view->SetBounds(10, 10, 50, 40);
3181 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3182 widget->GetRootView()->AddChildView(view);
3184 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3187 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3188 generator.set_current_location(gfx::Point(20, 20));
3190 generator.ClickLeftButton();
3191 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3192 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3193 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3195 generator.PressRightButton();
3196 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3197 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3198 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3200 generator.ReleaseRightButton();
3201 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3202 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3203 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3205 // Test mouse move events.
3206 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3207 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3209 // Move the mouse within the view (20, 20) -> (30, 30).
3210 generator.MoveMouseTo(gfx::Point(30, 30));
3211 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3212 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3213 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3215 // Move it again - entered count shouldn't change.
3216 generator.MoveMouseTo(gfx::Point(31, 31));
3217 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3218 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3219 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3221 // Move it off the view.
3222 generator.MoveMouseTo(gfx::Point(5, 5));
3223 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3224 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3225 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3228 generator.MoveMouseTo(gfx::Point(20, 20));
3229 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3230 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3231 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3233 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3234 generator.DragMouseTo(gfx::Point(40, 40));
3235 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3236 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3237 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3238 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3243 // Tests that the root view is correctly set up for Widget types that do not
3244 // require a non-client view, before any other views are added to the widget.
3245 // That is, before Widget::ReorderNativeViews() is called which, if called with
3246 // a root view not set, could cause the root view to get resized to the widget.
3247 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3248 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3249 View* root_view = widget->GetRootView();
3251 // Size the root view to exceed the widget bounds.
3252 const gfx::Rect test_rect(0, 0, 500, 500);
3253 root_view->SetBoundsRect(test_rect);
3255 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3257 EXPECT_EQ(test_rect, root_view->bounds());
3258 widget->ReorderNativeViews();
3259 EXPECT_EQ(test_rect, root_view->bounds());
3265 } // namespace views