Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobd4b5cb920dbeeb3dd31a9d03141fcda63648d1f4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <set>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_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"
35 #if defined(OS_WIN)
36 #include "ui/views/win/hwnd_util.h"
37 #endif
39 namespace views {
40 namespace test {
42 namespace {
44 // TODO(tdanderson): This utility function is used in different unittest
45 // files. Move to a common location to avoid
46 // repeated code.
47 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
48 gfx::Point tmp(p);
49 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
50 return tmp;
53 } // namespace
55 // A view that keeps track of the events it receives, optionally consuming them.
56 class EventCountView : public View {
57 public:
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.
61 enum HandleMode {
62 PROPAGATE_EVENTS,
63 CONSUME_EVENTS
66 EventCountView()
67 : last_flags_(0),
68 handle_mode_(PROPAGATE_EVENTS) {}
70 ~EventCountView() override {}
72 int GetEventCount(ui::EventType type) {
73 return event_count_[type];
76 void ResetCounts() {
77 event_count_.clear();
80 int last_flags() const {
81 return last_flags_;
84 void set_handle_mode(HandleMode handle_mode) {
85 handle_mode_ = handle_mode;
88 protected:
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];
93 last_flags_ = 0;
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); }
102 private:
103 void RecordEvent(ui::Event* event) {
104 ++event_count_[event->type()];
105 last_flags_ = event->flags();
106 if (handle_mode_ == CONSUME_EVENTS)
107 event->SetHandled();
110 std::map<ui::EventType, int> event_count_;
111 int last_flags_;
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 {
120 public:
121 ScrollableEventCountView() {}
122 ~ScrollableEventCountView() override {}
124 private:
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:
133 event->SetHandled();
134 break;
135 default:
136 break;
140 void OnScrollEvent(ui::ScrollEvent* event) override {
141 EventCountView::OnScrollEvent(event);
142 if (event->type() == ui::ET_SCROLL)
143 event->SetHandled();
146 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
149 // A view that implements GetMinimumSize.
150 class MinimumSizeFrameView : public NativeFrameView {
151 public:
152 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
153 ~MinimumSizeFrameView() override {}
155 private:
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
163 // it receives.
164 class EventCountHandler : public ui::EventHandler {
165 public:
166 EventCountHandler() {}
167 ~EventCountHandler() override {}
169 int GetEventCount(ui::EventType type) {
170 return event_count_[type];
173 void ResetCounts() {
174 event_count_.clear();
177 protected:
178 // Overridden from ui::EventHandler:
179 void OnEvent(ui::Event* event) override {
180 RecordEvent(*event);
181 ui::EventHandler::OnEvent(event);
184 private:
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 {
197 public:
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();
208 } else {
209 View::OnEvent(event);
210 if (!event->IsTouchEvent())
211 event->SetHandled();
215 private:
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();
259 top1->Show();
260 RunPendingMessages();
262 Widget* top2 = CreateTopLevelPlatformWidget();
263 top2->Show();
264 RunPendingMessages();
266 top1->Activate();
267 RunPendingMessages();
269 // Create InputMethod after deactivated.
270 top2->GetInputMethod();
271 top2->Activate();
272 RunPendingMessages();
274 top1->Activate();
275 RunPendingMessages();
277 top1->CloseNow();
278 top2->CloseNow();
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());
290 child->Show();
292 EXPECT_FALSE(toplevel->IsVisible());
293 EXPECT_FALSE(child->IsVisible());
295 toplevel->Show();
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 {
312 public:
313 WidgetOwnershipTest() {}
314 ~WidgetOwnershipTest() override {}
316 void SetUp() override {
317 WidgetTest::SetUp();
318 desktop_widget_ = CreateTopLevelPlatformWidget();
321 void TearDown() override {
322 desktop_widget_->CloseNow();
323 WidgetTest::TearDown();
326 private:
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) {}
336 bool widget_deleted;
337 bool native_widget_deleted;
340 // A platform NativeWidget subclass that updates a bag of state when it is
341 // destroyed.
342 class OwnershipTestNativeWidget : public PlatformNativeWidget {
343 public:
344 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
345 OwnershipTestState* state)
346 : PlatformNativeWidget(delegate),
347 state_(state) {
349 ~OwnershipTestNativeWidget() override {
350 state_->native_widget_deleted = true;
353 private:
354 OwnershipTestState* state_;
356 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
359 // A views NativeWidget subclass that updates a bag of state when it is
360 // destroyed.
361 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
362 public:
363 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
364 OwnershipTestState* state)
365 : NativeWidgetCapture(delegate),
366 state_(state) {
368 ~OwnershipTestNativeWidgetAura() override {
369 state_->native_widget_deleted = true;
372 private:
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 {
380 public:
381 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
382 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
384 private:
385 OwnershipTestState* state_;
387 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
390 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
391 // widget.
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.
403 widget.reset();
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.
424 widget.reset();
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.
460 widget.reset();
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
467 // widget.
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.
478 widget->CloseNow();
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.
569 widget->Close();
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.
597 widget.reset();
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 {
608 public:
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();
625 widget->IsClosed();
626 widget->Close();
627 widget->Hide();
628 widget->Activate();
629 widget->Deactivate();
630 widget->IsActive();
631 widget->DisableInactiveRendering();
632 widget->SetAlwaysOnTop(true);
633 widget->IsAlwaysOnTop();
634 widget->Maximize();
635 widget->Minimize();
636 widget->Restore();
637 widget->IsMaximized();
638 widget->IsFullscreen();
639 widget->SetOpacity(0);
640 widget->SetUseDragFrame(true);
641 widget->FlashFrame(true);
642 widget->IsVisible();
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();
652 widget->GetLayer();
653 widget->ReorderNativeViews();
654 widget->SetCapture(widget->GetRootView());
655 widget->ReleaseCapture();
656 widget->HasCapture();
657 widget->GetWorkAreaBoundsInScreen();
658 widget->IsTranslucentWindowOpacitySupported();
661 private:
662 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
665 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
667 Widget widget;
668 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
669 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
670 widget.Init(params);
671 widget.Show();
673 widget.native_widget_private()->CloseNow();
674 InvokeWidgetMethods(&widget);
676 #if !defined(OS_CHROMEOS)
678 Widget widget;
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;
682 widget.Init(params);
683 widget.Show();
685 widget.native_widget_private()->CloseNow();
686 InvokeWidgetMethods(&widget);
688 #endif
691 ////////////////////////////////////////////////////////////////////////////////
692 // Widget observer tests.
695 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
696 public:
697 WidgetObserverTest()
698 : active_(NULL),
699 widget_closed_(NULL),
700 widget_activated_(NULL),
701 widget_shown_(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)
711 active_ = NULL;
712 widget_closed_ = widget;
715 void OnWidgetActivationChanged(Widget* widget, bool active) override {
716 if (active) {
717 if (widget_activated_)
718 widget_activated_->Deactivate();
719 widget_activated_ = widget;
720 active_ = widget;
721 } else {
722 if (widget_activated_ == widget)
723 widget_activated_ = NULL;
724 widget_deactivated_ = widget;
728 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
729 if (visible)
730 widget_shown_ = widget;
731 else
732 widget_hidden_ = widget;
735 void OnWidgetBoundsChanged(Widget* widget,
736 const gfx::Rect& new_bounds) override {
737 widget_bounds_changed_ = widget;
740 void reset() {
741 active_ = NULL;
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);
753 return widget;
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_; }
764 private:
765 Widget* active_;
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();
781 toplevel1->Show();
782 toplevel2->Show();
784 reset();
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();
806 toplevel->Show();
807 child1->Show();
808 child2->Show();
810 reset();
812 child1->Hide();
813 EXPECT_EQ(child1, widget_hidden());
815 child2->Hide();
816 EXPECT_EQ(child2, widget_hidden());
818 child1->Show();
819 EXPECT_EQ(child1, widget_shown());
821 child2->Show();
822 EXPECT_EQ(child2, widget_shown());
824 toplevel->CloseNow();
827 TEST_F(WidgetObserverTest, DestroyBubble) {
828 Widget* anchor = CreateTopLevelPlatformWidget();
829 anchor->Show();
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();
837 anchor->Hide();
838 anchor->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 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
859 // by the NativeWidget implementation.
860 TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
861 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
862 // consistency across platforms.
863 Widget* widget = new Widget(); // Note: owned by NativeWidget.
864 widget->AddObserver(this);
866 EXPECT_FALSE(widget_bounds_changed());
868 // Init causes a bounds change, even while not showing.
869 widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW));
870 EXPECT_TRUE(widget_bounds_changed());
871 reset();
873 // Resizing while hidden, triggers a change.
874 widget->SetSize(gfx::Size(160, 100));
875 EXPECT_FALSE(widget->IsVisible());
876 EXPECT_TRUE(widget_bounds_changed());
877 reset();
879 // Setting the same size does nothing.
880 widget->SetSize(gfx::Size(160, 100));
881 EXPECT_FALSE(widget_bounds_changed());
882 reset();
884 // Showing does nothing to the bounds.
885 widget->Show();
886 EXPECT_TRUE(widget->IsVisible());
887 EXPECT_FALSE(widget_bounds_changed());
888 reset();
890 // Resizing while shown.
891 widget->SetSize(gfx::Size(170, 100));
892 EXPECT_TRUE(widget_bounds_changed());
893 reset();
895 // Resize to the same thing while shown does nothing.
896 widget->SetSize(gfx::Size(170, 100));
897 EXPECT_FALSE(widget_bounds_changed());
898 reset();
900 // No bounds change when closing.
901 widget->CloseNow();
902 EXPECT_FALSE(widget_bounds_changed());
905 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
906 // widget is visible and not maximized or fullscreen.
907 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
908 // Choose test coordinates away from edges and dimensions that are "small"
909 // (but not too small) to ensure the OS doesn't try to adjust them.
910 const gfx::Rect kTestBounds(150, 150, 400, 300);
911 const gfx::Size kTestSize(200, 180);
913 // First test a toplevel widget.
914 Widget* widget = CreateTopLevelPlatformWidget();
915 widget->Show();
917 EXPECT_NE(kTestSize.ToString(),
918 widget->GetWindowBoundsInScreen().size().ToString());
919 widget->SetSize(kTestSize);
920 EXPECT_EQ(kTestSize.ToString(),
921 widget->GetWindowBoundsInScreen().size().ToString());
923 EXPECT_NE(kTestBounds.ToString(),
924 widget->GetWindowBoundsInScreen().ToString());
925 widget->SetBounds(kTestBounds);
926 EXPECT_EQ(kTestBounds.ToString(),
927 widget->GetWindowBoundsInScreen().ToString());
929 // Changing just the size should not change the origin.
930 widget->SetSize(kTestSize);
931 EXPECT_EQ(kTestBounds.origin().ToString(),
932 widget->GetWindowBoundsInScreen().origin().ToString());
934 widget->CloseNow();
936 // Same tests with a frameless window.
937 widget = CreateTopLevelFramelessPlatformWidget();
938 widget->Show();
940 EXPECT_NE(kTestSize.ToString(),
941 widget->GetWindowBoundsInScreen().size().ToString());
942 widget->SetSize(kTestSize);
943 EXPECT_EQ(kTestSize.ToString(),
944 widget->GetWindowBoundsInScreen().size().ToString());
946 EXPECT_NE(kTestBounds.ToString(),
947 widget->GetWindowBoundsInScreen().ToString());
948 widget->SetBounds(kTestBounds);
949 EXPECT_EQ(kTestBounds.ToString(),
950 widget->GetWindowBoundsInScreen().ToString());
952 // For a frameless widget, the client bounds should also match.
953 EXPECT_EQ(kTestBounds.ToString(),
954 widget->GetClientAreaBoundsInScreen().ToString());
956 // Verify origin is stable for a frameless window as well.
957 widget->SetSize(kTestSize);
958 EXPECT_EQ(kTestBounds.origin().ToString(),
959 widget->GetWindowBoundsInScreen().origin().ToString());
961 widget->CloseNow();
964 // Before being enabled on Mac, this was #ifdef(false).
965 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
966 #if defined(OS_MACOSX)
967 // Aura needs shell to maximize/fullscreen window.
968 // NativeWidgetGtk doesn't implement GetRestoredBounds.
969 TEST_F(WidgetTest, GetRestoredBounds) {
970 Widget* toplevel = CreateTopLevelPlatformWidget();
971 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
972 toplevel->GetRestoredBounds().ToString());
973 toplevel->Show();
974 toplevel->Maximize();
975 RunPendingMessages();
976 #if defined(OS_MACOSX)
977 // Current expectation on Mac is to do nothing on Maximize.
978 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
979 toplevel->GetRestoredBounds().ToString());
980 #else
981 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
982 toplevel->GetRestoredBounds().ToString());
983 #endif
984 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
985 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
987 toplevel->Restore();
988 RunPendingMessages();
989 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
990 toplevel->GetRestoredBounds().ToString());
992 toplevel->SetFullscreen(true);
993 RunPendingMessages();
994 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
995 toplevel->GetRestoredBounds().ToString());
996 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
997 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
999 #endif
1001 // Test that window state is not changed after getting out of full screen.
1002 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
1003 Widget* toplevel = CreateTopLevelPlatformWidget();
1005 toplevel->Show();
1006 RunPendingMessages();
1008 // This should be a normal state window.
1009 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1011 toplevel->SetFullscreen(true);
1012 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
1013 toplevel->SetFullscreen(false);
1014 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
1016 // And it should still be in normal state after getting out of full screen.
1017 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
1019 // On Mac, a "maximized" state is indistinguishable from a window that just
1020 // fills the screen, so nothing to check there.
1021 #if !defined(OS_MACOSX)
1022 // Now, make it maximized.
1023 toplevel->Maximize();
1024 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
1026 toplevel->SetFullscreen(true);
1027 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
1028 toplevel->SetFullscreen(false);
1029 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
1031 // And it stays maximized after getting out of full screen.
1032 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
1033 #endif
1035 // Clean up.
1036 toplevel->Close();
1037 RunPendingMessages();
1040 // The key-event propagation from Widget happens differently on aura and
1041 // non-aura systems because of the difference in IME. So this test works only on
1042 // aura.
1043 TEST_F(WidgetTest, KeyboardInputEvent) {
1044 Widget* toplevel = CreateTopLevelPlatformWidget();
1045 View* container = toplevel->client_view();
1047 Textfield* textfield = new Textfield();
1048 textfield->SetText(base::ASCIIToUTF16("some text"));
1049 container->AddChildView(textfield);
1050 toplevel->Show();
1051 textfield->RequestFocus();
1053 // The press gets handled. The release doesn't have an effect.
1054 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1055 toplevel->OnKeyEvent(&backspace_p);
1056 EXPECT_TRUE(backspace_p.stopped_propagation());
1057 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1058 toplevel->OnKeyEvent(&backspace_r);
1059 EXPECT_FALSE(backspace_r.handled());
1061 toplevel->Close();
1064 // Verifies bubbles result in a focus lost when shown.
1065 // TODO(msw): this tests relies on focus, it needs to be in
1066 // interactive_ui_tests.
1067 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1068 // Create a widget, show and activate it and focus the contents view.
1069 View* contents_view = new View;
1070 contents_view->SetFocusable(true);
1071 Widget widget;
1072 Widget::InitParams init_params =
1073 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1074 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1075 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1076 #if !defined(OS_CHROMEOS)
1077 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1078 #endif
1079 widget.Init(init_params);
1080 widget.SetContentsView(contents_view);
1081 widget.Show();
1082 widget.Activate();
1083 contents_view->RequestFocus();
1084 EXPECT_TRUE(contents_view->HasFocus());
1086 // Show a bubble.
1087 BubbleDelegateView* bubble_delegate_view =
1088 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1089 bubble_delegate_view->SetFocusable(true);
1090 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1091 bubble_delegate_view->RequestFocus();
1093 // |contents_view_| should no longer have focus.
1094 EXPECT_FALSE(contents_view->HasFocus());
1095 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1097 bubble_delegate_view->GetWidget()->CloseNow();
1099 // Closing the bubble should result in focus going back to the contents view.
1100 EXPECT_TRUE(contents_view->HasFocus());
1103 class TestBubbleDelegateView : public BubbleDelegateView {
1104 public:
1105 TestBubbleDelegateView(View* anchor)
1106 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1107 reset_controls_called_(false) {}
1108 ~TestBubbleDelegateView() override {}
1110 bool ShouldShowCloseButton() const override {
1111 reset_controls_called_ = true;
1112 return true;
1115 mutable bool reset_controls_called_;
1118 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1119 Widget* anchor = CreateTopLevelPlatformWidget();
1120 anchor->Show();
1122 TestBubbleDelegateView* bubble_delegate =
1123 new TestBubbleDelegateView(anchor->client_view());
1124 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1125 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1126 bubble_widget->Show();
1127 bubble_widget->CloseNow();
1129 anchor->Hide();
1130 anchor->CloseNow();
1133 // Desktop native widget Aura tests are for non Chrome OS platforms.
1134 #if !defined(OS_CHROMEOS)
1135 // Test to ensure that after minimize, view width is set to zero.
1136 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1137 // Create a widget.
1138 Widget widget;
1139 Widget::InitParams init_params =
1140 CreateParams(Widget::InitParams::TYPE_WINDOW);
1141 init_params.show_state = ui::SHOW_STATE_NORMAL;
1142 gfx::Rect initial_bounds(0, 0, 300, 400);
1143 init_params.bounds = initial_bounds;
1144 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1145 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1146 widget.Init(init_params);
1147 NonClientView* non_client_view = widget.non_client_view();
1148 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1149 non_client_view->SetFrameView(frame_view);
1150 widget.Show();
1151 widget.Minimize();
1152 EXPECT_EQ(0, frame_view->width());
1155 // This class validates whether paints are received for a visible Widget.
1156 // To achieve this it overrides the Show and Close methods on the Widget class
1157 // and sets state whether subsequent paints are expected.
1158 class DesktopAuraTestValidPaintWidget : public views::Widget {
1159 public:
1160 DesktopAuraTestValidPaintWidget()
1161 : received_paint_(false),
1162 expect_paint_(true),
1163 received_paint_while_hidden_(false) {}
1165 ~DesktopAuraTestValidPaintWidget() override {}
1167 void InitForTest(Widget::InitParams create_params);
1169 void Show() override {
1170 expect_paint_ = true;
1171 views::Widget::Show();
1174 void Close() override {
1175 expect_paint_ = false;
1176 views::Widget::Close();
1179 void Hide() {
1180 expect_paint_ = false;
1181 views::Widget::Hide();
1184 void OnNativeWidgetPaint(gfx::Canvas* canvas) override {
1185 received_paint_ = true;
1186 EXPECT_TRUE(expect_paint_);
1187 if (!expect_paint_)
1188 received_paint_while_hidden_ = true;
1189 views::Widget::OnNativeWidgetPaint(canvas);
1192 bool ReadReceivedPaintAndReset() {
1193 bool result = received_paint_;
1194 received_paint_ = false;
1195 return result;
1198 bool received_paint_while_hidden() const {
1199 return received_paint_while_hidden_;
1202 private:
1203 bool received_paint_;
1204 bool expect_paint_;
1205 bool received_paint_while_hidden_;
1207 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1210 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1211 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1212 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1213 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1214 Init(init_params);
1216 View* contents_view = new View;
1217 contents_view->SetFocusable(true);
1218 SetContentsView(contents_view);
1220 Show();
1221 Activate();
1224 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1225 DesktopAuraTestValidPaintWidget widget;
1226 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1227 RunPendingMessages();
1228 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1229 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1230 widget.Close();
1231 RunPendingMessages();
1232 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1233 EXPECT_FALSE(widget.received_paint_while_hidden());
1236 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1237 DesktopAuraTestValidPaintWidget widget;
1238 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1239 RunPendingMessages();
1240 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1241 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1242 widget.Hide();
1243 RunPendingMessages();
1244 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1245 EXPECT_FALSE(widget.received_paint_while_hidden());
1246 widget.Close();
1249 // Test to ensure that the aura Window's visiblity state is set to visible if
1250 // the underlying widget is hidden and then shown.
1251 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1252 // Create a widget.
1253 Widget widget;
1254 Widget::InitParams init_params =
1255 CreateParams(Widget::InitParams::TYPE_WINDOW);
1256 init_params.show_state = ui::SHOW_STATE_NORMAL;
1257 gfx::Rect initial_bounds(0, 0, 300, 400);
1258 init_params.bounds = initial_bounds;
1259 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1260 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1261 widget.Init(init_params);
1262 NonClientView* non_client_view = widget.non_client_view();
1263 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1264 non_client_view->SetFrameView(frame_view);
1266 widget.Show();
1267 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1268 widget.Hide();
1269 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1270 widget.Show();
1271 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1274 // The following code verifies we can correctly destroy a Widget from a mouse
1275 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1276 // nested message loops from such events, nor has the code ever really dealt
1277 // with this situation.
1279 // Generates two moves (first generates enter, second real move), a press, drag
1280 // and release stopping at |last_event_type|.
1281 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1282 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1283 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1284 screen_bounds.CenterPoint(), 0, 0);
1285 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1286 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1287 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1288 return;
1289 details = dispatcher->OnEventFromSource(&move_event);
1290 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1291 return;
1293 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1294 screen_bounds.CenterPoint(), 0, 0);
1295 details = dispatcher->OnEventFromSource(&press_event);
1296 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1297 return;
1299 gfx::Point end_point(screen_bounds.CenterPoint());
1300 end_point.Offset(1, 1);
1301 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1302 details = dispatcher->OnEventFromSource(&drag_event);
1303 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1304 return;
1306 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1308 details = dispatcher->OnEventFromSource(&release_event);
1309 if (details.dispatcher_destroyed)
1310 return;
1313 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1314 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1315 ui::EventType last_event_type) {
1316 // |widget| is deleted by CloseWidgetView.
1317 Widget* widget = new Widget;
1318 Widget::InitParams params =
1319 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1320 params.native_widget = new PlatformDesktopNativeWidget(widget);
1321 params.bounds = gfx::Rect(0, 0, 50, 100);
1322 widget->Init(params);
1323 widget->SetContentsView(new CloseWidgetView(last_event_type));
1324 widget->Show();
1325 GenerateMouseEvents(widget, last_event_type);
1328 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1329 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1330 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1333 // Verifies deleting the widget from a mouse released event doesn't crash.
1334 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1335 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1338 #endif // !defined(OS_CHROMEOS)
1340 // Tests that wheel events generated from scroll events are targetted to the
1341 // views under the cursor when the focused view does not processed them.
1342 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1343 EventCountView* cursor_view = new EventCountView;
1344 cursor_view->SetBounds(60, 0, 50, 40);
1346 Widget* widget = CreateTopLevelPlatformWidget();
1347 widget->GetRootView()->AddChildView(cursor_view);
1349 // Generate a scroll event on the cursor view.
1350 ui::ScrollEvent scroll(ui::ET_SCROLL,
1351 gfx::Point(65, 5),
1352 ui::EventTimeForNow(),
1354 0, 20,
1355 0, 20,
1357 widget->OnScrollEvent(&scroll);
1359 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1360 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1362 cursor_view->ResetCounts();
1364 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1365 gfx::Point(5, 5),
1366 ui::EventTimeForNow(),
1368 0, 20,
1369 0, 20,
1371 widget->OnScrollEvent(&scroll2);
1373 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1374 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1376 widget->CloseNow();
1379 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1380 // events are not dispatched to any view.
1381 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1382 EventCountView* noscroll_view = new EventCountView;
1383 EventCountView* scroll_view = new ScrollableEventCountView;
1385 noscroll_view->SetBounds(0, 0, 50, 40);
1386 scroll_view->SetBounds(60, 0, 40, 40);
1388 Widget* widget = CreateTopLevelPlatformWidget();
1389 widget->GetRootView()->AddChildView(noscroll_view);
1390 widget->GetRootView()->AddChildView(scroll_view);
1393 ui::GestureEvent begin(
1397 base::TimeDelta(),
1398 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1399 widget->OnGestureEvent(&begin);
1400 ui::GestureEvent update(
1404 base::TimeDelta(),
1405 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1406 widget->OnGestureEvent(&update);
1407 ui::GestureEvent end(25,
1410 base::TimeDelta(),
1411 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1412 widget->OnGestureEvent(&end);
1414 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1415 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1416 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1420 ui::GestureEvent begin(
1424 base::TimeDelta(),
1425 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1426 widget->OnGestureEvent(&begin);
1427 ui::GestureEvent update(
1431 base::TimeDelta(),
1432 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1433 widget->OnGestureEvent(&update);
1434 ui::GestureEvent end(85,
1437 base::TimeDelta(),
1438 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1439 widget->OnGestureEvent(&end);
1441 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1442 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1443 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1446 widget->CloseNow();
1449 // Tests that event-handlers installed on the RootView get triggered correctly.
1450 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1451 TEST_F(WidgetTest, EventHandlersOnRootView) {
1452 Widget* widget = CreateTopLevelNativeWidget();
1453 View* root_view = widget->GetRootView();
1455 scoped_ptr<EventCountView> view(new EventCountView());
1456 view->set_owned_by_client();
1457 view->SetBounds(0, 0, 20, 20);
1458 root_view->AddChildView(view.get());
1460 EventCountHandler h1;
1461 root_view->AddPreTargetHandler(&h1);
1463 EventCountHandler h2;
1464 root_view->AddPostTargetHandler(&h2);
1466 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1467 widget->Show();
1469 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1470 // bubble up the views hierarchy to be re-dispatched on the root view.
1471 ui::ScrollEvent scroll(ui::ET_SCROLL,
1472 gfx::Point(5, 5),
1473 ui::EventTimeForNow(),
1475 0, 20,
1476 0, 20,
1478 widget->OnScrollEvent(&scroll);
1479 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1480 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1481 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1483 // Unhandled scroll events are turned into wheel events and re-dispatched.
1484 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1485 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1486 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1488 h1.ResetCounts();
1489 view->ResetCounts();
1490 h2.ResetCounts();
1492 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1493 // should bubble up the views hierarchy to be re-dispatched on the root view.
1494 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1495 gfx::Point(5, 5),
1496 ui::EventTimeForNow(),
1498 0, 20,
1499 0, 20,
1501 widget->OnScrollEvent(&fling);
1502 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1503 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1504 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1506 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1507 // be turned into wheel events and re-dispatched.
1508 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1509 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1510 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1512 h1.ResetCounts();
1513 view->ResetCounts();
1514 h2.ResetCounts();
1516 // Change the handle mode of |view| so that events are marked as handled at
1517 // the target phase.
1518 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1520 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1521 // The events are handled at the target phase and should not reach the
1522 // post-target handler.
1523 ui::GestureEvent tap_down(5,
1526 ui::EventTimeForNow(),
1527 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1528 widget->OnGestureEvent(&tap_down);
1529 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1530 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1531 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1533 ui::GestureEvent tap_cancel(
1537 ui::EventTimeForNow(),
1538 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1539 widget->OnGestureEvent(&tap_cancel);
1540 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1541 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1542 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1544 h1.ResetCounts();
1545 view->ResetCounts();
1546 h2.ResetCounts();
1548 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1549 // and should not reach the post-target handler.
1550 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1551 gfx::Point(5, 5),
1552 ui::EventTimeForNow(),
1554 0, 20,
1555 0, 20,
1557 widget->OnScrollEvent(&consumed_scroll);
1558 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1559 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1560 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1562 // Handled scroll events are not turned into wheel events and re-dispatched.
1563 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1564 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1565 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1567 widget->CloseNow();
1570 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1571 Widget* widget = CreateTopLevelNativeWidget();
1572 View* root_view = widget->GetRootView();
1574 EventCountView* v1 = new EventCountView();
1575 v1->SetBounds(0, 0, 10, 10);
1576 root_view->AddChildView(v1);
1577 EventCountView* v2 = new EventCountView();
1578 v2->SetBounds(0, 10, 10, 10);
1579 root_view->AddChildView(v2);
1581 gfx::Point cursor_location(5, 5);
1582 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1583 ui::EF_NONE, ui::EF_NONE);
1584 widget->OnMouseEvent(&move);
1586 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1587 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1589 delete v1;
1590 v2->SetBounds(0, 0, 10, 10);
1591 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1593 widget->SynthesizeMouseMoveEvent();
1594 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1597 namespace {
1599 // ui::EventHandler which handles all mouse press events.
1600 class MousePressEventConsumer : public ui::EventHandler {
1601 public:
1602 explicit MousePressEventConsumer() {
1605 ~MousePressEventConsumer() override {}
1607 private:
1608 // ui::EventHandler:
1609 void OnMouseEvent(ui::MouseEvent* event) override {
1610 if (event->type() == ui::ET_MOUSE_PRESSED)
1611 event->SetHandled();
1614 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1617 } // namespace
1619 // Test that mouse presses and mouse releases are dispatched normally when a
1620 // touch is down.
1621 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1622 Widget* widget = CreateTopLevelNativeWidget();
1623 widget->Show();
1624 widget->SetSize(gfx::Size(300, 300));
1626 EventCountView* event_count_view = new EventCountView();
1627 event_count_view->SetBounds(0, 0, 300, 300);
1628 widget->GetRootView()->AddChildView(event_count_view);
1630 MousePressEventConsumer consumer;
1631 event_count_view->AddPostTargetHandler(&consumer);
1633 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1634 generator.PressTouch();
1635 generator.ClickLeftButton();
1637 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1638 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1640 widget->CloseNow();
1643 // Used by SingleWindowClosing to count number of times WindowClosing() has
1644 // been invoked.
1645 class ClosingDelegate : public WidgetDelegate {
1646 public:
1647 ClosingDelegate() : count_(0), widget_(NULL) {}
1649 int count() const { return count_; }
1651 void set_widget(views::Widget* widget) { widget_ = widget; }
1653 // WidgetDelegate overrides:
1654 Widget* GetWidget() override { return widget_; }
1655 const Widget* GetWidget() const override { return widget_; }
1656 void WindowClosing() override { count_++; }
1658 private:
1659 int count_;
1660 views::Widget* widget_;
1662 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1665 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1666 // is closed.
1667 TEST_F(WidgetTest, SingleWindowClosing) {
1668 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1669 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1670 Widget::InitParams init_params =
1671 CreateParams(Widget::InitParams::TYPE_WINDOW);
1672 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1673 init_params.delegate = delegate.get();
1674 #if !defined(OS_CHROMEOS)
1675 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1676 #endif
1677 widget->Init(init_params);
1678 EXPECT_EQ(0, delegate->count());
1679 widget->CloseNow();
1680 EXPECT_EQ(1, delegate->count());
1683 class WidgetWindowTitleTest : public WidgetTest {
1684 protected:
1685 void RunTest(bool desktop_native_widget) {
1686 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1687 Widget::InitParams init_params =
1688 CreateParams(Widget::InitParams::TYPE_WINDOW);
1689 widget->Init(init_params);
1691 #if !defined(OS_CHROMEOS)
1692 if (desktop_native_widget)
1693 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1694 #else
1695 DCHECK(!desktop_native_widget)
1696 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1697 #endif
1699 internal::NativeWidgetPrivate* native_widget =
1700 widget->native_widget_private();
1702 base::string16 empty;
1703 base::string16 s1(base::UTF8ToUTF16("Title1"));
1704 base::string16 s2(base::UTF8ToUTF16("Title2"));
1705 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1707 // The widget starts with no title, setting empty should not change
1708 // anything.
1709 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1710 // Setting the title to something non-empty should cause a change.
1711 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1712 // Setting the title to something else with the same length should cause a
1713 // change.
1714 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1715 // Setting the title to something else with a different length should cause
1716 // a change.
1717 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1718 // Setting the title to the same thing twice should not cause a change.
1719 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1721 widget->CloseNow();
1725 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1726 // Use the default NativeWidget.
1727 bool desktop_native_widget = false;
1728 RunTest(desktop_native_widget);
1731 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1732 #if !defined(OS_CHROMEOS)
1733 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1734 // Override to use a DesktopNativeWidget.
1735 bool desktop_native_widget = true;
1736 RunTest(desktop_native_widget);
1738 #endif // !OS_CHROMEOS
1740 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1741 Widget* widget = new Widget;
1742 Widget::InitParams params =
1743 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1744 widget->Init(params);
1746 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1748 widget->SetSize(gfx::Size(100, 100));
1749 widget->Show();
1751 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1753 WidgetDeletionObserver deletion_observer(widget);
1754 generator.ClickLeftButton();
1755 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1757 // Yay we did not crash!
1760 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1761 Widget* widget = new Widget;
1762 Widget::InitParams params =
1763 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1764 widget->Init(params);
1766 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1768 widget->SetSize(gfx::Size(100, 100));
1769 widget->Show();
1771 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1773 WidgetDeletionObserver deletion_observer(widget);
1774 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1775 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1777 // Yay we did not crash!
1780 // See description of RunGetNativeThemeFromDestructor() for details.
1781 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1782 public:
1783 GetNativeThemeFromDestructorView() {}
1784 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1786 View* GetContentsView() override { return this; }
1788 private:
1789 void VerifyNativeTheme() {
1790 ASSERT_TRUE(GetNativeTheme() != NULL);
1793 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1796 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1797 // crash. |is_first_run| is true if this is the first call. A return value of
1798 // true indicates this should be run again with a value of false.
1799 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1800 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1801 bool is_first_run) {
1802 bool needs_second_run = false;
1803 // Destroyed by CloseNow() below.
1804 Widget* widget = new Widget;
1805 Widget::InitParams params(in_params);
1806 // Deletes itself when the Widget is destroyed.
1807 params.delegate = new GetNativeThemeFromDestructorView;
1808 #if !defined(OS_CHROMEOS)
1809 if (is_first_run) {
1810 params.native_widget = new PlatformDesktopNativeWidget(widget);
1811 needs_second_run = true;
1813 #endif
1814 widget->Init(params);
1815 widget->CloseNow();
1816 return needs_second_run;
1819 // See description of RunGetNativeThemeFromDestructor() for details.
1820 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1821 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1822 if (RunGetNativeThemeFromDestructor(params, true))
1823 RunGetNativeThemeFromDestructor(params, false);
1826 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1827 // destroyed.
1828 class CloseDestroysWidget : public Widget {
1829 public:
1830 explicit CloseDestroysWidget(bool* destroyed)
1831 : destroyed_(destroyed) {
1834 ~CloseDestroysWidget() override {
1835 if (destroyed_) {
1836 *destroyed_ = true;
1837 base::MessageLoop::current()->QuitNow();
1841 void Detach() { destroyed_ = NULL; }
1843 private:
1844 // If non-null set to true from destructor.
1845 bool* destroyed_;
1847 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1850 // An observer that registers that an animation has ended.
1851 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1852 public:
1853 AnimationEndObserver() : animation_completed_(false) {}
1854 ~AnimationEndObserver() override {}
1856 bool animation_completed() const { return animation_completed_; }
1858 // ui::ImplicitAnimationObserver:
1859 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
1861 private:
1862 bool animation_completed_;
1864 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1867 // An observer that registers the bounds of a widget on destruction.
1868 class WidgetBoundsObserver : public WidgetObserver {
1869 public:
1870 WidgetBoundsObserver() {}
1871 ~WidgetBoundsObserver() override {}
1873 gfx::Rect bounds() { return bounds_; }
1875 // WidgetObserver:
1876 void OnWidgetDestroying(Widget* widget) override {
1877 bounds_ = widget->GetWindowBoundsInScreen();
1880 private:
1881 gfx::Rect bounds_;
1883 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1886 // Verifies Close() results in destroying.
1887 TEST_F(WidgetTest, CloseDestroys) {
1888 bool destroyed = false;
1889 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1890 Widget::InitParams params =
1891 CreateParams(views::Widget::InitParams::TYPE_MENU);
1892 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1893 #if !defined(OS_CHROMEOS)
1894 params.native_widget = new PlatformDesktopNativeWidget(widget);
1895 #endif
1896 widget->Init(params);
1897 widget->Show();
1898 widget->Hide();
1899 widget->Close();
1900 EXPECT_FALSE(destroyed);
1901 // Run the message loop as Close() asynchronously deletes.
1902 base::RunLoop().Run();
1903 EXPECT_TRUE(destroyed);
1904 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1905 if (!destroyed) {
1906 widget->Detach();
1907 widget->CloseNow();
1911 // Tests that killing a widget while animating it does not crash.
1912 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1913 scoped_ptr<Widget> widget(new Widget);
1914 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1915 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1916 params.bounds = gfx::Rect(50, 50, 250, 250);
1917 widget->Init(params);
1918 AnimationEndObserver animation_observer;
1919 WidgetBoundsObserver widget_observer;
1920 gfx::Rect bounds(0, 0, 50, 50);
1922 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1923 // animating the movement.
1924 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1925 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1926 ui::ScopedLayerAnimationSettings animation_settings(
1927 widget->GetLayer()->GetAnimator());
1928 animation_settings.AddObserver(&animation_observer);
1929 widget->AddObserver(&widget_observer);
1930 widget->Show();
1932 // Animate the bounds change.
1933 widget->SetBounds(bounds);
1934 widget.reset();
1935 EXPECT_FALSE(animation_observer.animation_completed());
1937 EXPECT_TRUE(animation_observer.animation_completed());
1938 EXPECT_EQ(widget_observer.bounds(), bounds);
1941 // A view that consumes mouse-pressed event and gesture-tap-down events.
1942 class RootViewTestView : public View {
1943 public:
1944 RootViewTestView(): View() {}
1946 private:
1947 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
1949 void OnGestureEvent(ui::GestureEvent* event) override {
1950 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1951 event->SetHandled();
1955 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1956 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1957 #if defined(OS_WIN)
1958 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1959 DISABLED_TestRootViewHandlersWhenHidden
1960 #else
1961 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1962 TestRootViewHandlersWhenHidden
1963 #endif
1964 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1965 Widget* widget = CreateTopLevelNativeWidget();
1966 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1967 View* view = new RootViewTestView();
1968 view->SetBounds(0, 0, 300, 300);
1969 internal::RootView* root_view =
1970 static_cast<internal::RootView*>(widget->GetRootView());
1971 root_view->AddChildView(view);
1973 // Check RootView::mouse_pressed_handler_.
1974 widget->Show();
1975 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1976 gfx::Point click_location(45, 15);
1977 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1978 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1979 widget->OnMouseEvent(&press);
1980 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1981 widget->Hide();
1982 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1984 // Check RootView::mouse_move_handler_.
1985 widget->Show();
1986 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1987 gfx::Point move_location(45, 15);
1988 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1989 widget->OnMouseEvent(&move);
1990 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1991 widget->Hide();
1992 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1994 // Check RootView::gesture_handler_.
1995 widget->Show();
1996 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1997 ui::GestureEvent tap_down(15,
2000 base::TimeDelta(),
2001 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2002 widget->OnGestureEvent(&tap_down);
2003 EXPECT_EQ(view, GetGestureHandler(root_view));
2004 widget->Hide();
2005 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2007 widget->Close();
2010 // Convenience to make constructing a GestureEvent simpler.
2011 class GestureEventForTest : public ui::GestureEvent {
2012 public:
2013 GestureEventForTest(ui::EventType type, int x, int y)
2014 : GestureEvent(x,
2017 base::TimeDelta(),
2018 ui::GestureEventDetails(type)) {}
2020 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2021 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2024 // Tests that the |gesture_handler_| member in RootView is always NULL
2025 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2026 // the release of the final touch point on the screen, but that
2027 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2028 // point do not modify |gesture_handler_|.
2029 TEST_F(WidgetTest, GestureEndEvents) {
2030 Widget* widget = CreateTopLevelNativeWidget();
2031 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2032 EventCountView* view = new EventCountView();
2033 view->SetBounds(0, 0, 300, 300);
2034 internal::RootView* root_view =
2035 static_cast<internal::RootView*>(widget->GetRootView());
2036 root_view->AddChildView(view);
2037 widget->Show();
2039 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2040 // the gesture handler.
2041 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2042 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2043 widget->OnGestureEvent(&end);
2044 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2046 // Change the handle mode of |view| to indicate that it would like
2047 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2048 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2049 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2050 widget->OnGestureEvent(&tap);
2051 EXPECT_TRUE(tap.handled());
2052 EXPECT_EQ(view, GetGestureHandler(root_view));
2054 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2055 // corresponding to a second touch point, but should be reset to NULL by a
2056 // ui::ET_GESTURE_END corresponding to the final touch point.
2057 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2058 details.set_touch_points(2);
2059 GestureEventForTest end_second_touch_point(details, 15, 15);
2060 widget->OnGestureEvent(&end_second_touch_point);
2061 EXPECT_EQ(view, GetGestureHandler(root_view));
2063 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2064 widget->OnGestureEvent(&end);
2065 EXPECT_TRUE(end.handled());
2066 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2068 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2069 // mode of |view| to indicate that it does not want to handle any
2070 // further events.
2071 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2072 widget->OnGestureEvent(&tap);
2073 EXPECT_TRUE(tap.handled());
2074 EXPECT_EQ(view, GetGestureHandler(root_view));
2075 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2077 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2078 // corresponding to a second touch point, but should be reset to NULL by a
2079 // ui::ET_GESTURE_END corresponding to the final touch point.
2080 end_second_touch_point = GestureEventForTest(details, 15, 15);
2081 widget->OnGestureEvent(&end_second_touch_point);
2082 EXPECT_EQ(view, GetGestureHandler(root_view));
2084 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2085 widget->OnGestureEvent(&end);
2086 EXPECT_FALSE(end.handled());
2087 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2089 widget->Close();
2092 // Tests that gesture events which should not be processed (because
2093 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2094 // dispatched to any views.
2095 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2096 Widget* widget = CreateTopLevelNativeWidget();
2097 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2099 // Define a hierarchy of four views (coordinates are in
2100 // their parent coordinate space).
2101 // v1 (0, 0, 300, 300)
2102 // v2 (0, 0, 100, 100)
2103 // v3 (0, 0, 50, 50)
2104 // v4(0, 0, 10, 10)
2105 EventCountView* v1 = new EventCountView();
2106 v1->SetBounds(0, 0, 300, 300);
2107 EventCountView* v2 = new EventCountView();
2108 v2->SetBounds(0, 0, 100, 100);
2109 EventCountView* v3 = new EventCountView();
2110 v3->SetBounds(0, 0, 50, 50);
2111 EventCountView* v4 = new EventCountView();
2112 v4->SetBounds(0, 0, 10, 10);
2113 internal::RootView* root_view =
2114 static_cast<internal::RootView*>(widget->GetRootView());
2115 root_view->AddChildView(v1);
2116 v1->AddChildView(v2);
2117 v2->AddChildView(v3);
2118 v3->AddChildView(v4);
2120 widget->Show();
2122 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2123 // they should be marked as handled by OnEventProcessingStarted().
2124 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2125 widget->OnGestureEvent(&begin);
2126 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2127 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2128 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2129 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2130 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2131 EXPECT_TRUE(begin.handled());
2132 v1->ResetCounts();
2133 v2->ResetCounts();
2134 v3->ResetCounts();
2135 v4->ResetCounts();
2137 // ui::ET_GESTURE_END events should not be seen by any view when there is
2138 // no default gesture handler set, but they should be marked as handled by
2139 // OnEventProcessingStarted().
2140 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2141 widget->OnGestureEvent(&end);
2142 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2143 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2144 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2145 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2146 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2147 EXPECT_TRUE(end.handled());
2148 v1->ResetCounts();
2149 v2->ResetCounts();
2150 v3->ResetCounts();
2151 v4->ResetCounts();
2153 // ui::ET_GESTURE_END events not corresponding to the release of the
2154 // final touch point should never be seen by any view, but they should
2155 // be marked as handled by OnEventProcessingStarted().
2156 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2157 details.set_touch_points(2);
2158 GestureEventForTest end_second_touch_point(details, 5, 5);
2159 widget->OnGestureEvent(&end_second_touch_point);
2160 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2161 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2162 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2163 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2164 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2165 EXPECT_TRUE(end_second_touch_point.handled());
2166 v1->ResetCounts();
2167 v2->ResetCounts();
2168 v3->ResetCounts();
2169 v4->ResetCounts();
2171 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2172 // there is no default gesture handler set, but they should be marked as
2173 // handled by OnEventProcessingStarted().
2174 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2175 widget->OnGestureEvent(&scroll_update);
2176 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2177 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2178 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2179 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2180 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2181 EXPECT_TRUE(scroll_update.handled());
2182 v1->ResetCounts();
2183 v2->ResetCounts();
2184 v3->ResetCounts();
2185 v4->ResetCounts();
2187 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2188 // there is no default gesture handler set, but they should be marked as
2189 // handled by OnEventProcessingStarted().
2190 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2191 widget->OnGestureEvent(&scroll_end);
2192 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2193 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2194 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2195 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2196 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2197 EXPECT_TRUE(scroll_end.handled());
2198 v1->ResetCounts();
2199 v2->ResetCounts();
2200 v3->ResetCounts();
2201 v4->ResetCounts();
2203 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2204 // there is no default gesture handler set, but they should be marked as
2205 // handled by OnEventProcessingStarted().
2206 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2207 widget->OnGestureEvent(&scroll_fling_start);
2208 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2209 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2210 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2211 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2212 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2213 EXPECT_TRUE(scroll_fling_start.handled());
2214 v1->ResetCounts();
2215 v2->ResetCounts();
2216 v3->ResetCounts();
2217 v4->ResetCounts();
2219 widget->Close();
2222 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2223 // in a view hierarchy and that the default gesture handler in RootView is set
2224 // correctly.
2225 TEST_F(WidgetTest, GestureEventDispatch) {
2226 Widget* widget = CreateTopLevelNativeWidget();
2227 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2229 // Define a hierarchy of four views (coordinates are in
2230 // their parent coordinate space).
2231 // v1 (0, 0, 300, 300)
2232 // v2 (0, 0, 100, 100)
2233 // v3 (0, 0, 50, 50)
2234 // v4(0, 0, 10, 10)
2235 EventCountView* v1 = new EventCountView();
2236 v1->SetBounds(0, 0, 300, 300);
2237 EventCountView* v2 = new EventCountView();
2238 v2->SetBounds(0, 0, 100, 100);
2239 EventCountView* v3 = new EventCountView();
2240 v3->SetBounds(0, 0, 50, 50);
2241 EventCountView* v4 = new EventCountView();
2242 v4->SetBounds(0, 0, 10, 10);
2243 internal::RootView* root_view =
2244 static_cast<internal::RootView*>(widget->GetRootView());
2245 root_view->AddChildView(v1);
2246 v1->AddChildView(v2);
2247 v2->AddChildView(v3);
2248 v3->AddChildView(v4);
2250 widget->Show();
2252 // No gesture handler is set in the root view and none of the views in the
2253 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2254 // event should be dispatched to all views in the hierarchy, the gesture
2255 // handler should remain unset, and the event should remain unhandled.
2256 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2257 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2258 widget->OnGestureEvent(&tap);
2259 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2260 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2261 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2262 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2263 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2264 EXPECT_FALSE(tap.handled());
2266 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2267 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2268 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2269 // and the event should be marked as handled.
2270 v1->ResetCounts();
2271 v2->ResetCounts();
2272 v3->ResetCounts();
2273 v4->ResetCounts();
2274 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2275 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2276 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2277 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2278 widget->OnGestureEvent(&tap);
2279 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2280 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2281 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2282 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2283 EXPECT_EQ(v3, GetGestureHandler(root_view));
2284 EXPECT_TRUE(tap.handled());
2286 // The gesture handler is set to |v3| and all views handle all gesture event
2287 // types. In this case subsequent gesture events should only be dispatched to
2288 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2289 v1->ResetCounts();
2290 v2->ResetCounts();
2291 v3->ResetCounts();
2292 v4->ResetCounts();
2293 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2294 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2295 widget->OnGestureEvent(&tap);
2296 EXPECT_TRUE(tap.handled());
2297 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2298 widget->OnGestureEvent(&show_press);
2299 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2300 widget->OnGestureEvent(&tap);
2301 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2302 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2303 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2304 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2305 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2306 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2307 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2308 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2309 EXPECT_TRUE(tap.handled());
2310 EXPECT_TRUE(show_press.handled());
2311 EXPECT_EQ(v3, GetGestureHandler(root_view));
2313 // The gesture handler is set to |v3|, but |v3| does not handle
2314 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2315 // only to |v3|, but the event should remain unhandled. The gesture handler
2316 // should remain as |v3|.
2317 v1->ResetCounts();
2318 v2->ResetCounts();
2319 v3->ResetCounts();
2320 v4->ResetCounts();
2321 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2322 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2323 widget->OnGestureEvent(&tap);
2324 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2325 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2326 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2327 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2328 EXPECT_FALSE(tap.handled());
2329 EXPECT_EQ(v3, GetGestureHandler(root_view));
2331 widget->Close();
2334 // Tests that gesture scroll events will change the default gesture handler in
2335 // RootView if the current handler to which they are dispatched does not handle
2336 // gesture scroll events.
2337 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2338 Widget* widget = CreateTopLevelNativeWidget();
2339 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2341 // Define a hierarchy of four views (coordinates are in
2342 // their parent coordinate space).
2343 // v1 (0, 0, 300, 300)
2344 // v2 (0, 0, 100, 100)
2345 // v3 (0, 0, 50, 50)
2346 // v4(0, 0, 10, 10)
2347 EventCountView* v1 = new EventCountView();
2348 v1->SetBounds(0, 0, 300, 300);
2349 EventCountView* v2 = new EventCountView();
2350 v2->SetBounds(0, 0, 100, 100);
2351 EventCountView* v3 = new EventCountView();
2352 v3->SetBounds(0, 0, 50, 50);
2353 EventCountView* v4 = new EventCountView();
2354 v4->SetBounds(0, 0, 10, 10);
2355 internal::RootView* root_view =
2356 static_cast<internal::RootView*>(widget->GetRootView());
2357 root_view->AddChildView(v1);
2358 v1->AddChildView(v2);
2359 v2->AddChildView(v3);
2360 v3->AddChildView(v4);
2362 widget->Show();
2364 // Change the handle mode of |v3| to indicate that it would like to handle
2365 // gesture events.
2366 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2368 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2369 // should bubble up the views hierarchy until it reaches the first view
2370 // that will handle it (|v3|) and then sets the handler to |v3|.
2371 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2372 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2373 widget->OnGestureEvent(&tap_down);
2374 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2375 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2376 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2377 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2378 EXPECT_EQ(v3, GetGestureHandler(root_view));
2379 EXPECT_TRUE(tap_down.handled());
2380 v1->ResetCounts();
2381 v2->ResetCounts();
2382 v3->ResetCounts();
2383 v4->ResetCounts();
2385 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2386 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2387 widget->OnGestureEvent(&tap_cancel);
2388 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2389 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2390 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2391 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2392 EXPECT_EQ(v3, GetGestureHandler(root_view));
2393 EXPECT_TRUE(tap_cancel.handled());
2394 v1->ResetCounts();
2395 v2->ResetCounts();
2396 v3->ResetCounts();
2397 v4->ResetCounts();
2399 // Change the handle mode of |v3| to indicate that it would no longer like
2400 // to handle events, and change the mode of |v1| to indicate that it would
2401 // like to handle events.
2402 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2403 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2405 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2406 // handler (|v3|) does not handle scroll events, the event should bubble up
2407 // the views hierarchy until it reaches the first view that will handle
2408 // it (|v1|) and then sets the handler to |v1|.
2409 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2410 widget->OnGestureEvent(&scroll_begin);
2411 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2412 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2413 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2414 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2415 EXPECT_EQ(v1, GetGestureHandler(root_view));
2416 EXPECT_TRUE(scroll_begin.handled());
2417 v1->ResetCounts();
2418 v2->ResetCounts();
2419 v3->ResetCounts();
2420 v4->ResetCounts();
2422 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2423 // directly.
2424 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2425 widget->OnGestureEvent(&scroll_update);
2426 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2427 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2428 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2429 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2430 EXPECT_EQ(v1, GetGestureHandler(root_view));
2431 EXPECT_TRUE(scroll_update.handled());
2432 v1->ResetCounts();
2433 v2->ResetCounts();
2434 v3->ResetCounts();
2435 v4->ResetCounts();
2437 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2438 // directly and should not reset the gesture handler.
2439 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2440 widget->OnGestureEvent(&scroll_end);
2441 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2442 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2443 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2444 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2445 EXPECT_EQ(v1, GetGestureHandler(root_view));
2446 EXPECT_TRUE(scroll_end.handled());
2447 v1->ResetCounts();
2448 v2->ResetCounts();
2449 v3->ResetCounts();
2450 v4->ResetCounts();
2452 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2453 // still be dispatched to |v1| directly.
2454 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2455 widget->OnGestureEvent(&pinch_begin);
2456 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2457 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2458 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2459 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2460 EXPECT_EQ(v1, GetGestureHandler(root_view));
2461 EXPECT_TRUE(pinch_begin.handled());
2462 v1->ResetCounts();
2463 v2->ResetCounts();
2464 v3->ResetCounts();
2465 v4->ResetCounts();
2467 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2468 // set the gesture handler to NULL.
2469 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2470 widget->OnGestureEvent(&end);
2471 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2472 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2473 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2474 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2475 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2476 EXPECT_TRUE(end.handled());
2478 widget->Close();
2481 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2482 // that when a gesture event bubbles up a View hierarchy, the location
2483 // of a gesture event seen by each View is in the local coordinate space
2484 // of that View.
2485 class GestureLocationView : public EventCountView {
2486 public:
2487 GestureLocationView() {}
2488 ~GestureLocationView() override {}
2490 void set_expected_location(gfx::Point expected_location) {
2491 expected_location_ = expected_location;
2494 // EventCountView:
2495 void OnGestureEvent(ui::GestureEvent* event) override {
2496 EventCountView::OnGestureEvent(event);
2498 // Verify that the location of |event| is in the local coordinate
2499 // space of |this|.
2500 EXPECT_EQ(expected_location_, event->location());
2503 private:
2504 // The expected location of a gesture event dispatched to |this|.
2505 gfx::Point expected_location_;
2507 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2510 // Verifies that the location of a gesture event is always in the local
2511 // coordinate space of the View receiving the event while bubbling.
2512 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2513 Widget* widget = CreateTopLevelNativeWidget();
2514 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2516 // Define a hierarchy of three views (coordinates shown below are in the
2517 // coordinate space of the root view, but the coordinates used for
2518 // SetBounds() are in their parent coordinate space).
2519 // v1 (50, 50, 150, 150)
2520 // v2 (100, 70, 50, 80)
2521 // v3 (120, 100, 10, 10)
2522 GestureLocationView* v1 = new GestureLocationView();
2523 v1->SetBounds(50, 50, 150, 150);
2524 GestureLocationView* v2 = new GestureLocationView();
2525 v2->SetBounds(50, 20, 50, 80);
2526 GestureLocationView* v3 = new GestureLocationView();
2527 v3->SetBounds(20, 30, 10, 10);
2528 internal::RootView* root_view =
2529 static_cast<internal::RootView*>(widget->GetRootView());
2530 root_view->AddChildView(v1);
2531 v1->AddChildView(v2);
2532 v2->AddChildView(v3);
2534 widget->Show();
2536 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2537 // This event is contained within all of |v1|, |v2|, and |v3|.
2538 gfx::Point location_in_root(125, 105);
2539 GestureEventForTest tap(
2540 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2542 // Calculate the location of the event in the local coordinate spaces
2543 // of each of the views.
2544 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2545 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2546 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2547 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2548 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2549 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2551 // Dispatch the event. When each view receives the event, its location should
2552 // be in the local coordinate space of that view (see the check made by
2553 // GestureLocationView). After dispatch is complete the event's location
2554 // should be in the root coordinate space.
2555 v1->set_expected_location(location_in_v1);
2556 v2->set_expected_location(location_in_v2);
2557 v3->set_expected_location(location_in_v3);
2558 widget->OnGestureEvent(&tap);
2559 EXPECT_EQ(location_in_root, tap.location());
2561 // Verify that each view did in fact see the event.
2562 EventCountView* view1 = v1;
2563 EventCountView* view2 = v2;
2564 EventCountView* view3 = v3;
2565 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2566 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2567 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2569 widget->Close();
2572 // Verifies that disabled views are permitted to be set as the default gesture
2573 // handler in RootView. Also verifies that gesture events targeted to a disabled
2574 // view are not actually dispatched to the view, but are still marked as
2575 // handled.
2576 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2577 Widget* widget = CreateTopLevelNativeWidget();
2578 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2580 // Define a hierarchy of four views (coordinates are in
2581 // their parent coordinate space).
2582 // v1 (0, 0, 300, 300)
2583 // v2 (0, 0, 100, 100)
2584 // v3 (0, 0, 50, 50)
2585 // v4(0, 0, 10, 10)
2586 EventCountView* v1 = new EventCountView();
2587 v1->SetBounds(0, 0, 300, 300);
2588 EventCountView* v2 = new EventCountView();
2589 v2->SetBounds(0, 0, 100, 100);
2590 EventCountView* v3 = new EventCountView();
2591 v3->SetBounds(0, 0, 50, 50);
2592 EventCountView* v4 = new EventCountView();
2593 v4->SetBounds(0, 0, 10, 10);
2594 internal::RootView* root_view =
2595 static_cast<internal::RootView*>(widget->GetRootView());
2596 root_view->AddChildView(v1);
2597 v1->AddChildView(v2);
2598 v2->AddChildView(v3);
2599 v3->AddChildView(v4);
2601 widget->Show();
2603 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2604 // disabled.
2605 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2606 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2607 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2608 v3->SetEnabled(false);
2610 // No gesture handler is set in the root view. In this case the tap event
2611 // should be dispatched only to |v4|, the gesture handler should be set to
2612 // |v3|, and the event should be marked as handled.
2613 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2614 widget->OnGestureEvent(&tap);
2615 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2616 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2617 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2618 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2619 EXPECT_EQ(v3, GetGestureHandler(root_view));
2620 EXPECT_TRUE(tap.handled());
2621 v1->ResetCounts();
2622 v2->ResetCounts();
2623 v3->ResetCounts();
2624 v4->ResetCounts();
2626 // A subsequent gesture event should be marked as handled but not dispatched.
2627 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2628 widget->OnGestureEvent(&tap);
2629 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2630 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2631 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2632 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2633 EXPECT_EQ(v3, GetGestureHandler(root_view));
2634 EXPECT_TRUE(tap.handled());
2635 v1->ResetCounts();
2636 v2->ResetCounts();
2637 v3->ResetCounts();
2638 v4->ResetCounts();
2640 // A GESTURE_END should reset the default gesture handler to NULL. It should
2641 // also not be dispatched to |v3| but still marked as handled.
2642 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2643 widget->OnGestureEvent(&end);
2644 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2645 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2646 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2647 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2648 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2649 EXPECT_TRUE(end.handled());
2650 v1->ResetCounts();
2651 v2->ResetCounts();
2652 v3->ResetCounts();
2653 v4->ResetCounts();
2655 // Change the handle mode of |v3| to indicate that it would no longer like
2656 // to handle events which are dispatched to it.
2657 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2659 // No gesture handler is set in the root view. In this case the tap event
2660 // should be dispatched only to |v4| and the event should be marked as
2661 // handled. Furthermore, the gesture handler should be set to
2662 // |v3|; even though |v3| does not explicitly handle events, it is a
2663 // valid target for the tap event because it is disabled.
2664 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2665 widget->OnGestureEvent(&tap);
2666 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2667 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2668 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2669 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2670 EXPECT_EQ(v3, GetGestureHandler(root_view));
2671 EXPECT_TRUE(tap.handled());
2672 v1->ResetCounts();
2673 v2->ResetCounts();
2674 v3->ResetCounts();
2675 v4->ResetCounts();
2677 // A GESTURE_END should reset the default gesture handler to NULL. It should
2678 // also not be dispatched to |v3| but still marked as handled.
2679 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2680 widget->OnGestureEvent(&end);
2681 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2682 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2683 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2684 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2685 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2686 EXPECT_TRUE(end.handled());
2688 widget->Close();
2691 // Test the result of Widget::GetAllChildWidgets().
2692 TEST_F(WidgetTest, GetAllChildWidgets) {
2693 // Create the following widget hierarchy:
2695 // toplevel
2696 // +-- w1
2697 // +-- w11
2698 // +-- w2
2699 // +-- w21
2700 // +-- w22
2701 Widget* toplevel = CreateTopLevelPlatformWidget();
2702 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2703 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2704 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2705 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2706 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2708 std::set<Widget*> expected;
2709 expected.insert(toplevel);
2710 expected.insert(w1);
2711 expected.insert(w11);
2712 expected.insert(w2);
2713 expected.insert(w21);
2714 expected.insert(w22);
2716 std::set<Widget*> widgets;
2717 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2719 EXPECT_EQ(expected.size(), widgets.size());
2720 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2723 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2724 // a vector.
2725 class DestroyedTrackingView : public View {
2726 public:
2727 DestroyedTrackingView(const std::string& name,
2728 std::vector<std::string>* add_to)
2729 : name_(name),
2730 add_to_(add_to) {
2733 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2735 private:
2736 const std::string name_;
2737 std::vector<std::string>* add_to_;
2739 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2742 class WidgetChildDestructionTest : public WidgetTest {
2743 public:
2744 WidgetChildDestructionTest() {}
2746 // Creates a top level and a child, destroys the child and verifies the views
2747 // of the child are destroyed before the views of the parent.
2748 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2749 bool child_has_desktop_native_widget_aura) {
2750 // When a View is destroyed its name is added here.
2751 std::vector<std::string> destroyed;
2753 Widget* top_level = new Widget;
2754 Widget::InitParams params =
2755 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2756 #if !defined(OS_CHROMEOS)
2757 if (top_level_has_desktop_native_widget_aura)
2758 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2759 #endif
2760 top_level->Init(params);
2761 top_level->GetRootView()->AddChildView(
2762 new DestroyedTrackingView("parent", &destroyed));
2763 top_level->Show();
2765 Widget* child = new Widget;
2766 Widget::InitParams child_params =
2767 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2768 child_params.parent = top_level->GetNativeView();
2769 #if !defined(OS_CHROMEOS)
2770 if (child_has_desktop_native_widget_aura)
2771 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2772 #endif
2773 child->Init(child_params);
2774 child->GetRootView()->AddChildView(
2775 new DestroyedTrackingView("child", &destroyed));
2776 child->Show();
2778 // Should trigger destruction of the child too.
2779 top_level->native_widget_private()->CloseNow();
2781 // Child should be destroyed first.
2782 ASSERT_EQ(2u, destroyed.size());
2783 EXPECT_EQ("child", destroyed[0]);
2784 EXPECT_EQ("parent", destroyed[1]);
2787 private:
2788 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2791 #if !defined(OS_CHROMEOS)
2792 // See description of RunDestroyChildWidgetsTest(). Parent uses
2793 // DesktopNativeWidgetAura.
2794 TEST_F(WidgetChildDestructionTest,
2795 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2796 RunDestroyChildWidgetsTest(true, false);
2799 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2800 // DesktopNativeWidgetAura.
2801 TEST_F(WidgetChildDestructionTest,
2802 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2803 RunDestroyChildWidgetsTest(true, true);
2805 #endif // !defined(OS_CHROMEOS)
2807 // See description of RunDestroyChildWidgetsTest().
2808 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2809 RunDestroyChildWidgetsTest(false, false);
2812 #if !defined(OS_CHROMEOS)
2813 // Provides functionality to create a window modal dialog.
2814 class ModalDialogDelegate : public DialogDelegateView {
2815 public:
2816 ModalDialogDelegate() {}
2817 ~ModalDialogDelegate() override {}
2819 // WidgetDelegate overrides.
2820 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
2822 private:
2823 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2826 // This test verifies that whether mouse events when a modal dialog is
2827 // displayed are eaten or recieved by the dialog.
2828 TEST_F(WidgetTest, WindowMouseModalityTest) {
2829 // Create a top level widget.
2830 Widget top_level_widget;
2831 Widget::InitParams init_params =
2832 CreateParams(Widget::InitParams::TYPE_WINDOW);
2833 init_params.show_state = ui::SHOW_STATE_NORMAL;
2834 gfx::Rect initial_bounds(0, 0, 500, 500);
2835 init_params.bounds = initial_bounds;
2836 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2837 init_params.native_widget =
2838 new PlatformDesktopNativeWidget(&top_level_widget);
2839 top_level_widget.Init(init_params);
2840 top_level_widget.Show();
2841 EXPECT_TRUE(top_level_widget.IsVisible());
2843 // Create a view and validate that a mouse moves makes it to the view.
2844 EventCountView* widget_view = new EventCountView();
2845 widget_view->SetBounds(0, 0, 10, 10);
2846 top_level_widget.GetRootView()->AddChildView(widget_view);
2848 gfx::Point cursor_location_main(5, 5);
2849 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2850 cursor_location_main,
2851 cursor_location_main,
2852 ui::EF_NONE,
2853 ui::EF_NONE);
2854 ui::EventDispatchDetails details =
2855 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2856 ASSERT_FALSE(details.dispatcher_destroyed);
2858 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2859 widget_view->ResetCounts();
2861 // Create a modal dialog and validate that a mouse down message makes it to
2862 // the main view within the dialog.
2864 // This instance will be destroyed when the dialog is destroyed.
2865 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2867 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2868 dialog_delegate, NULL, top_level_widget.GetNativeView());
2869 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2870 EventCountView* dialog_widget_view = new EventCountView();
2871 dialog_widget_view->SetBounds(0, 0, 50, 50);
2872 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2873 modal_dialog_widget->Show();
2874 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2876 gfx::Point cursor_location_dialog(100, 100);
2877 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2878 cursor_location_dialog,
2879 cursor_location_dialog,
2880 ui::EF_NONE,
2881 ui::EF_NONE);
2882 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2883 &mouse_down_dialog);
2884 ASSERT_FALSE(details.dispatcher_destroyed);
2885 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2887 // Send a mouse move message to the main window. It should not be received by
2888 // the main window as the modal dialog is still active.
2889 gfx::Point cursor_location_main2(6, 6);
2890 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2891 cursor_location_main2,
2892 cursor_location_main2,
2893 ui::EF_NONE,
2894 ui::EF_NONE);
2895 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2896 &mouse_down_main);
2897 ASSERT_FALSE(details.dispatcher_destroyed);
2898 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2900 modal_dialog_widget->CloseNow();
2901 top_level_widget.CloseNow();
2904 // Verifies nativeview visbility matches that of Widget visibility when
2905 // SetFullscreen is invoked.
2906 TEST_F(WidgetTest, FullscreenStatePropagated) {
2907 Widget::InitParams init_params =
2908 CreateParams(Widget::InitParams::TYPE_WINDOW);
2909 init_params.show_state = ui::SHOW_STATE_NORMAL;
2910 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2911 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2914 Widget top_level_widget;
2915 top_level_widget.Init(init_params);
2916 top_level_widget.SetFullscreen(true);
2917 EXPECT_EQ(top_level_widget.IsVisible(),
2918 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2919 top_level_widget.CloseNow();
2921 #if !defined(OS_CHROMEOS)
2923 Widget top_level_widget;
2924 init_params.native_widget =
2925 new PlatformDesktopNativeWidget(&top_level_widget);
2926 top_level_widget.Init(init_params);
2927 top_level_widget.SetFullscreen(true);
2928 EXPECT_EQ(top_level_widget.IsVisible(),
2929 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2930 top_level_widget.CloseNow();
2932 #endif
2934 #if defined(OS_WIN)
2936 // Provides functionality to test widget activation via an activation flag
2937 // which can be set by an accessor.
2938 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2939 public:
2940 ModalWindowTestWidgetDelegate()
2941 : widget_(NULL),
2942 can_activate_(true) {}
2944 virtual ~ModalWindowTestWidgetDelegate() {}
2946 // Overridden from WidgetDelegate:
2947 virtual void DeleteDelegate() override {
2948 delete this;
2950 virtual Widget* GetWidget() override {
2951 return widget_;
2953 virtual const Widget* GetWidget() const override {
2954 return widget_;
2956 virtual bool CanActivate() const override {
2957 return can_activate_;
2959 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
2960 return true;
2963 void set_can_activate(bool can_activate) {
2964 can_activate_ = can_activate;
2967 void set_widget(Widget* widget) {
2968 widget_ = widget;
2971 private:
2972 Widget* widget_;
2973 bool can_activate_;
2975 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2978 // Tests whether we can activate the top level widget when a modal dialog is
2979 // active.
2980 TEST_F(WidgetTest, WindowModalityActivationTest) {
2981 // Destroyed when the top level widget created below is destroyed.
2982 ModalWindowTestWidgetDelegate* widget_delegate =
2983 new ModalWindowTestWidgetDelegate;
2984 // Create a top level widget.
2985 Widget top_level_widget;
2986 Widget::InitParams init_params =
2987 CreateParams(Widget::InitParams::TYPE_WINDOW);
2988 init_params.show_state = ui::SHOW_STATE_NORMAL;
2989 gfx::Rect initial_bounds(0, 0, 500, 500);
2990 init_params.bounds = initial_bounds;
2991 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2992 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2993 init_params.delegate = widget_delegate;
2994 top_level_widget.Init(init_params);
2995 widget_delegate->set_widget(&top_level_widget);
2996 top_level_widget.Show();
2997 EXPECT_TRUE(top_level_widget.IsVisible());
2999 HWND win32_window = views::HWNDForWidget(&top_level_widget);
3000 EXPECT_TRUE(::IsWindow(win32_window));
3002 // This instance will be destroyed when the dialog is destroyed.
3003 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3005 // We should be able to activate the window even if the WidgetDelegate
3006 // says no, when a modal dialog is active.
3007 widget_delegate->set_can_activate(false);
3009 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3010 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
3011 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3012 modal_dialog_widget->Show();
3013 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3015 LRESULT activate_result = ::SendMessage(
3016 win32_window,
3017 WM_MOUSEACTIVATE,
3018 reinterpret_cast<WPARAM>(win32_window),
3019 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
3020 EXPECT_EQ(activate_result, MA_ACTIVATE);
3022 modal_dialog_widget->CloseNow();
3023 top_level_widget.CloseNow();
3025 #endif // defined(OS_WIN)
3026 #endif // !defined(OS_CHROMEOS)
3028 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
3029 Widget* widget = CreateTopLevelPlatformWidget();
3031 widget->Show();
3032 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3034 widget->CloseNow();
3037 // OSX does not have a per-application "active" window such as provided by
3038 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
3039 // is updated asynchronously.
3040 #if defined(OS_MACOSX)
3041 #define MAYBE_ShowInactive DISABLED_ShowInactive
3042 #else
3043 #define MAYBE_ShowInactive ShowInactive
3044 #endif
3045 TEST_F(WidgetTest, MAYBE_ShowInactive) {
3046 Widget* widget = CreateTopLevelPlatformWidget();
3048 widget->ShowInactive();
3049 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
3051 widget->CloseNow();
3054 TEST_F(WidgetTest, InactiveBeforeShow) {
3055 Widget* widget = CreateTopLevelPlatformWidget();
3057 EXPECT_FALSE(widget->IsActive());
3058 EXPECT_FALSE(widget->IsVisible());
3060 widget->Show();
3062 EXPECT_TRUE(widget->IsActive());
3063 EXPECT_TRUE(widget->IsVisible());
3065 widget->CloseNow();
3068 TEST_F(WidgetTest, ShowInactiveAfterShow) {
3069 // Create 2 widgets to ensure window layering does not change.
3070 Widget* widget = CreateTopLevelPlatformWidget();
3071 Widget* widget2 = CreateTopLevelPlatformWidget();
3073 widget2->Show();
3074 EXPECT_FALSE(widget->IsActive());
3075 EXPECT_TRUE(widget2->IsVisible());
3076 EXPECT_TRUE(widget2->IsActive());
3078 widget->Show();
3079 EXPECT_TRUE(widget->IsActive());
3080 EXPECT_FALSE(widget2->IsActive());
3081 widget->ShowInactive();
3082 EXPECT_TRUE(widget->IsActive());
3083 EXPECT_FALSE(widget2->IsActive());
3084 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3086 widget2->CloseNow();
3087 widget->CloseNow();
3090 TEST_F(WidgetTest, ShowAfterShowInactive) {
3091 Widget* widget = CreateTopLevelPlatformWidget();
3093 widget->ShowInactive();
3094 widget->Show();
3095 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3097 widget->CloseNow();
3100 #if !defined(OS_CHROMEOS)
3101 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
3102 Widget* widget = CreateTopLevelPlatformWidget();
3103 widget->Show();
3104 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3106 Widget widget2;
3107 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3108 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
3109 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3110 widget2.Init(params);
3111 widget2.Show();
3113 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
3114 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3116 widget->CloseNow();
3117 widget2.CloseNow();
3119 #endif // !defined(OS_CHROMEOS)
3121 namespace {
3123 class FullscreenAwareFrame : public views::NonClientFrameView {
3124 public:
3125 explicit FullscreenAwareFrame(views::Widget* widget)
3126 : widget_(widget), fullscreen_layout_called_(false) {}
3127 ~FullscreenAwareFrame() override {}
3129 // views::NonClientFrameView overrides:
3130 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3131 gfx::Rect GetWindowBoundsForClientBounds(
3132 const gfx::Rect& client_bounds) const override {
3133 return gfx::Rect();
3135 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3136 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3137 void ResetWindowControls() override {}
3138 void UpdateWindowIcon() override {}
3139 void UpdateWindowTitle() override {}
3140 void SizeConstraintsChanged() override {}
3142 // views::View overrides:
3143 void Layout() override {
3144 if (widget_->IsFullscreen())
3145 fullscreen_layout_called_ = true;
3148 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3150 private:
3151 views::Widget* widget_;
3152 bool fullscreen_layout_called_;
3154 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3157 } // namespace
3159 // Tests that frame Layout is called when a widget goes fullscreen without
3160 // changing its size or title.
3161 TEST_F(WidgetTest, FullscreenFrameLayout) {
3162 Widget* widget = CreateTopLevelPlatformWidget();
3163 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3164 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3166 widget->Maximize();
3167 RunPendingMessages();
3169 EXPECT_FALSE(frame->fullscreen_layout_called());
3170 widget->SetFullscreen(true);
3171 widget->Show();
3172 RunPendingMessages();
3173 EXPECT_TRUE(frame->fullscreen_layout_called());
3175 widget->CloseNow();
3178 #if !defined(OS_CHROMEOS)
3179 namespace {
3181 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3182 // OnWindowDestroying.
3183 class IsActiveFromDestroyObserver : public WidgetObserver {
3184 public:
3185 IsActiveFromDestroyObserver() {}
3186 ~IsActiveFromDestroyObserver() override {}
3187 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3189 private:
3190 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3193 } // namespace
3195 // Verifies Widget::IsActive() invoked from
3196 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3197 TEST_F(WidgetTest, IsActiveFromDestroy) {
3198 // Create two widgets, one a child of the other.
3199 IsActiveFromDestroyObserver observer;
3200 Widget parent_widget;
3201 Widget::InitParams parent_params =
3202 CreateParams(Widget::InitParams::TYPE_POPUP);
3203 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3204 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3205 parent_widget.Init(parent_params);
3206 parent_widget.Show();
3208 Widget child_widget;
3209 Widget::InitParams child_params =
3210 CreateParams(Widget::InitParams::TYPE_POPUP);
3211 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3212 child_params.context = parent_widget.GetNativeWindow();
3213 child_widget.Init(child_params);
3214 child_widget.AddObserver(&observer);
3215 child_widget.Show();
3217 parent_widget.CloseNow();
3219 #endif // !defined(OS_CHROMEOS)
3221 // Tests that events propagate through from the dispatcher with the correct
3222 // event type, and that the different platforms behave the same.
3223 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3224 EventCountView* view = new EventCountView;
3225 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3226 view->SetBounds(10, 10, 50, 40);
3228 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3229 widget->GetRootView()->AddChildView(view);
3231 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3232 widget->Show();
3234 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3235 generator.set_current_location(gfx::Point(20, 20));
3237 generator.ClickLeftButton();
3238 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3239 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3240 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3242 generator.PressRightButton();
3243 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3244 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3245 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3247 generator.ReleaseRightButton();
3248 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3249 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3250 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3252 // Test mouse move events.
3253 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3254 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3256 // Move the mouse within the view (20, 20) -> (30, 30).
3257 generator.MoveMouseTo(gfx::Point(30, 30));
3258 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3259 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3260 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3262 // Move it again - entered count shouldn't change.
3263 generator.MoveMouseTo(gfx::Point(31, 31));
3264 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3265 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3266 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3268 // Move it off the view.
3269 generator.MoveMouseTo(gfx::Point(5, 5));
3270 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3271 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3272 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3274 // Move it back on.
3275 generator.MoveMouseTo(gfx::Point(20, 20));
3276 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3277 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3278 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3280 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3281 generator.DragMouseTo(gfx::Point(40, 40));
3282 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3283 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3284 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3285 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3287 widget->CloseNow();
3290 // Tests that the root view is correctly set up for Widget types that do not
3291 // require a non-client view, before any other views are added to the widget.
3292 // That is, before Widget::ReorderNativeViews() is called which, if called with
3293 // a root view not set, could cause the root view to get resized to the widget.
3294 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3295 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3296 View* root_view = widget->GetRootView();
3298 // Size the root view to exceed the widget bounds.
3299 const gfx::Rect test_rect(0, 0, 500, 500);
3300 root_view->SetBoundsRect(test_rect);
3302 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3304 EXPECT_EQ(test_rect, root_view->bounds());
3305 widget->ReorderNativeViews();
3306 EXPECT_EQ(test_rect, root_view->bounds());
3308 widget->CloseNow();
3311 } // namespace test
3312 } // namespace views