Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blobb564366fd0672cfa209ba25c840b3d917a7653dc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <set>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/events/test/event_generator.h"
21 #include "ui/gfx/geometry/point.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/views/bubble/bubble_delegate.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/test/test_views.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/test_widget_observer.h"
28 #include "ui/views/test/widget_test.h"
29 #include "ui/views/views_delegate.h"
30 #include "ui/views/widget/native_widget_delegate.h"
31 #include "ui/views/widget/root_view.h"
32 #include "ui/views/widget/widget_deletion_observer.h"
33 #include "ui/views/window/dialog_delegate.h"
34 #include "ui/views/window/native_frame_view.h"
36 #if defined(OS_WIN)
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_tree_host.h"
39 #include "ui/base/view_prop.h"
40 #include "ui/base/win/window_event_target.h"
41 #include "ui/views/win/hwnd_util.h"
42 #endif
44 #if defined(OS_MACOSX)
45 #include "base/mac/mac_util.h"
46 #endif
48 namespace views {
49 namespace test {
51 namespace {
53 // TODO(tdanderson): This utility function is used in different unittest
54 // files. Move to a common location to avoid
55 // repeated code.
56 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
57 gfx::Point tmp(p);
58 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
59 return tmp;
62 // Helper function for Snow Leopard special cases to avoid #ifdef litter.
63 bool IsTestingSnowLeopard() {
64 #if defined(OS_MACOSX)
65 return base::mac::IsOSSnowLeopard();
66 #else
67 return false;
68 #endif
71 } // namespace
73 // A view that keeps track of the events it receives, optionally consuming them.
74 class EventCountView : public View {
75 public:
76 // Whether to call SetHandled() on events as they are received. For some event
77 // types, this will allow EventCountView to receives future events in the
78 // event sequence, such as a drag.
79 enum HandleMode {
80 PROPAGATE_EVENTS,
81 CONSUME_EVENTS
84 EventCountView()
85 : last_flags_(0),
86 handle_mode_(PROPAGATE_EVENTS) {}
88 ~EventCountView() override {}
90 int GetEventCount(ui::EventType type) {
91 return event_count_[type];
94 void ResetCounts() {
95 event_count_.clear();
98 int last_flags() const {
99 return last_flags_;
102 void set_handle_mode(HandleMode handle_mode) {
103 handle_mode_ = handle_mode;
106 protected:
107 // Overridden from View:
108 void OnMouseMoved(const ui::MouseEvent& event) override {
109 // MouseMove events are not re-dispatched from the RootView.
110 ++event_count_[ui::ET_MOUSE_MOVED];
111 last_flags_ = 0;
114 // Overridden from ui::EventHandler:
115 void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); }
116 void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); }
117 void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); }
118 void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); }
120 private:
121 void RecordEvent(ui::Event* event) {
122 ++event_count_[event->type()];
123 last_flags_ = event->flags();
124 if (handle_mode_ == CONSUME_EVENTS)
125 event->SetHandled();
128 std::map<ui::EventType, int> event_count_;
129 int last_flags_;
130 HandleMode handle_mode_;
132 DISALLOW_COPY_AND_ASSIGN(EventCountView);
135 // A view that keeps track of the events it receives, and consumes all scroll
136 // gesture events and ui::ET_SCROLL events.
137 class ScrollableEventCountView : public EventCountView {
138 public:
139 ScrollableEventCountView() {}
140 ~ScrollableEventCountView() override {}
142 private:
143 // Overridden from ui::EventHandler:
144 void OnGestureEvent(ui::GestureEvent* event) override {
145 EventCountView::OnGestureEvent(event);
146 switch (event->type()) {
147 case ui::ET_GESTURE_SCROLL_BEGIN:
148 case ui::ET_GESTURE_SCROLL_UPDATE:
149 case ui::ET_GESTURE_SCROLL_END:
150 case ui::ET_SCROLL_FLING_START:
151 event->SetHandled();
152 break;
153 default:
154 break;
158 void OnScrollEvent(ui::ScrollEvent* event) override {
159 EventCountView::OnScrollEvent(event);
160 if (event->type() == ui::ET_SCROLL)
161 event->SetHandled();
164 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
167 // A view that implements GetMinimumSize.
168 class MinimumSizeFrameView : public NativeFrameView {
169 public:
170 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
171 ~MinimumSizeFrameView() override {}
173 private:
174 // Overridden from View:
175 gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
177 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
180 // An event handler that simply keeps a count of the different types of events
181 // it receives.
182 class EventCountHandler : public ui::EventHandler {
183 public:
184 EventCountHandler() {}
185 ~EventCountHandler() override {}
187 int GetEventCount(ui::EventType type) {
188 return event_count_[type];
191 void ResetCounts() {
192 event_count_.clear();
195 protected:
196 // Overridden from ui::EventHandler:
197 void OnEvent(ui::Event* event) override {
198 RecordEvent(*event);
199 ui::EventHandler::OnEvent(event);
202 private:
203 void RecordEvent(const ui::Event& event) {
204 ++event_count_[event.type()];
207 std::map<ui::EventType, int> event_count_;
209 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
212 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate
213 // calls, and removes some of the boilerplate for initializing a Widget. Calls
214 // Widget::CloseNow() when destroyed if it hasn't already been done.
215 class TestDesktopWidgetDelegate : public WidgetDelegate {
216 public:
217 TestDesktopWidgetDelegate() : widget_(new Widget) {}
219 ~TestDesktopWidgetDelegate() override {
220 if (widget_)
221 widget_->CloseNow();
222 EXPECT_FALSE(widget_);
225 // Initialize the Widget, adding some meaningful default InitParams.
226 void InitWidget(Widget::InitParams init_params) {
227 init_params.delegate = this;
228 #if !defined(OS_CHROMEOS)
229 init_params.native_widget = new PlatformDesktopNativeWidget(widget_);
230 #endif
231 init_params.bounds = initial_bounds_;
232 widget_->Init(init_params);
235 // Set the contents view to be used during Widget initialization. For Widgets
236 // that use non-client views, this will be the contents_view used to
237 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise,
238 // it is the ContentsView of the Widget's RootView. Ownership passes to the
239 // view hierarchy during InitWidget().
240 void set_contents_view(View* contents_view) {
241 contents_view_ = contents_view;
244 int window_closing_count() const { return window_closing_count_; }
245 const gfx::Rect& initial_bounds() { return initial_bounds_; }
247 // WidgetDelegate overrides:
248 void WindowClosing() override {
249 window_closing_count_++;
250 widget_ = nullptr;
253 Widget* GetWidget() override { return widget_; }
254 const Widget* GetWidget() const override { return widget_; }
256 View* GetContentsView() override {
257 return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView();
260 bool ShouldAdvanceFocusToTopLevelWidget() const override {
261 return true; // Same default as DefaultWidgetDelegate in widget.cc.
264 private:
265 Widget* widget_;
266 View* contents_view_ = nullptr;
267 int window_closing_count_ = 0;
268 gfx::Rect initial_bounds_ = gfx::Rect(100, 100, 200, 200);
270 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate);
273 TEST_F(WidgetTest, WidgetInitParams) {
274 // Widgets are not transparent by default.
275 Widget::InitParams init1;
276 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
279 TEST_F(WidgetTest, NativeWindowProperty) {
280 const char* key = "foo";
281 int value = 3;
283 Widget* widget = CreateTopLevelPlatformWidget();
284 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
286 widget->SetNativeWindowProperty(key, &value);
287 EXPECT_EQ(&value, widget->GetNativeWindowProperty(key));
289 widget->SetNativeWindowProperty(key, nullptr);
290 EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
292 widget->CloseNow();
295 ////////////////////////////////////////////////////////////////////////////////
296 // Widget::GetTopLevelWidget tests.
298 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
299 // Create a hierarchy of native widgets.
300 Widget* toplevel = CreateTopLevelPlatformWidget();
301 gfx::NativeView parent = toplevel->GetNativeView();
302 Widget* child = CreateChildPlatformWidget(parent);
304 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
305 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
307 toplevel->CloseNow();
308 // |child| should be automatically destroyed with |toplevel|.
311 // Test if a focus manager and an inputmethod work without CHECK failure
312 // when window activation changes.
313 TEST_F(WidgetTest, ChangeActivation) {
314 Widget* top1 = CreateTopLevelPlatformWidget();
315 // CreateInputMethod before activated
316 top1->GetInputMethod();
317 top1->Show();
318 RunPendingMessages();
320 Widget* top2 = CreateTopLevelPlatformWidget();
321 top2->Show();
322 RunPendingMessages();
324 top1->Activate();
325 RunPendingMessages();
327 // Create InputMethod after deactivated.
328 top2->GetInputMethod();
329 top2->Activate();
330 RunPendingMessages();
332 top1->Activate();
333 RunPendingMessages();
335 top1->CloseNow();
336 top2->CloseNow();
339 // Tests visibility of child widgets.
340 TEST_F(WidgetTest, Visibility) {
341 Widget* toplevel = CreateTopLevelPlatformWidget();
342 gfx::NativeView parent = toplevel->GetNativeView();
343 Widget* child = CreateChildPlatformWidget(parent);
345 EXPECT_FALSE(toplevel->IsVisible());
346 EXPECT_FALSE(child->IsVisible());
348 // Showing a child with a hidden parent keeps the child hidden.
349 child->Show();
350 EXPECT_FALSE(toplevel->IsVisible());
351 EXPECT_FALSE(child->IsVisible());
353 // Showing a hidden parent with a visible child shows both.
354 toplevel->Show();
355 EXPECT_TRUE(toplevel->IsVisible());
356 EXPECT_TRUE(child->IsVisible());
358 // Hiding a parent hides both parent and child.
359 toplevel->Hide();
360 EXPECT_FALSE(toplevel->IsVisible());
361 EXPECT_FALSE(child->IsVisible());
363 // Hiding a child while the parent is hidden keeps the child hidden when the
364 // parent is shown.
365 child->Hide();
366 toplevel->Show();
367 EXPECT_TRUE(toplevel->IsVisible());
368 EXPECT_FALSE(child->IsVisible());
370 toplevel->CloseNow();
371 // |child| should be automatically destroyed with |toplevel|.
374 // Test that child widgets are positioned relative to their parent.
375 TEST_F(WidgetTest, ChildBoundsRelativeToParent) {
376 Widget* toplevel = CreateTopLevelPlatformWidget();
377 Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
379 toplevel->SetBounds(gfx::Rect(160, 100, 320, 200));
380 child->SetBounds(gfx::Rect(0, 0, 320, 200));
382 child->Show();
383 toplevel->Show();
385 gfx::Rect toplevel_bounds = toplevel->GetWindowBoundsInScreen();
387 // Check the parent origin. If it was (0, 0) the test wouldn't be interesting.
388 EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds.OffsetFromOrigin());
390 // The child's origin is at (0, 0), but the same size, so bounds should match.
391 EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen());
393 toplevel->CloseNow();
396 // Test z-order of child widgets relative to their parent.
397 TEST_F(WidgetTest, ChildStackedRelativeToParent) {
398 Widget* parent = CreateTopLevelPlatformWidget();
399 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
401 parent->SetBounds(gfx::Rect(160, 100, 320, 200));
402 child->SetBounds(gfx::Rect(50, 50, 30, 20));
404 // Child shown first. Initially not visible, but on top of parent when shown.
405 // Use ShowInactive whenever showing the child, otherwise the usual activation
406 // logic will just put it on top anyway. Here, we want to ensure it is on top
407 // of its parent regardless.
408 child->ShowInactive();
409 EXPECT_FALSE(child->IsVisible());
411 parent->Show();
412 EXPECT_TRUE(child->IsVisible());
413 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
414 EXPECT_FALSE(IsWindowStackedAbove(parent, child)); // Sanity check.
416 Widget* popover = CreateTopLevelPlatformWidget();
417 popover->SetBounds(gfx::Rect(150, 90, 340, 240));
418 popover->Show();
420 EXPECT_TRUE(IsWindowStackedAbove(popover, child));
421 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
423 // Showing the parent again should raise it and its child above the popover.
424 parent->Show();
425 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
426 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
428 // Test grandchildren.
429 Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView());
430 grandchild->SetBounds(gfx::Rect(5, 5, 15, 10));
431 grandchild->ShowInactive();
432 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
433 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
434 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
436 popover->Show();
437 EXPECT_TRUE(IsWindowStackedAbove(popover, grandchild));
438 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
440 parent->Show();
441 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
442 EXPECT_TRUE(IsWindowStackedAbove(child, popover));
444 // Test hiding and reshowing.
445 parent->Hide();
446 EXPECT_FALSE(grandchild->IsVisible());
447 parent->Show();
449 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
450 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
451 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
453 grandchild->Hide();
454 EXPECT_FALSE(grandchild->IsVisible());
455 grandchild->ShowInactive();
457 EXPECT_TRUE(IsWindowStackedAbove(grandchild, child));
458 EXPECT_TRUE(IsWindowStackedAbove(child, parent));
459 EXPECT_TRUE(IsWindowStackedAbove(parent, popover));
461 popover->CloseNow();
462 parent->CloseNow();
465 ////////////////////////////////////////////////////////////////////////////////
466 // Widget ownership tests.
468 // Tests various permutations of Widget ownership specified in the
469 // InitParams::Ownership param.
471 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
472 class WidgetOwnershipTest : public WidgetTest {
473 public:
474 WidgetOwnershipTest() {}
475 ~WidgetOwnershipTest() override {}
477 void SetUp() override {
478 WidgetTest::SetUp();
479 desktop_widget_ = CreateTopLevelPlatformWidget();
482 void TearDown() override {
483 desktop_widget_->CloseNow();
484 WidgetTest::TearDown();
487 private:
488 Widget* desktop_widget_;
490 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
493 // A bag of state to monitor destructions.
494 struct OwnershipTestState {
495 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
497 bool widget_deleted;
498 bool native_widget_deleted;
501 // A platform NativeWidget subclass that updates a bag of state when it is
502 // destroyed.
503 class OwnershipTestNativeWidget : public PlatformNativeWidget {
504 public:
505 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
506 OwnershipTestState* state)
507 : PlatformNativeWidget(delegate),
508 state_(state) {
510 ~OwnershipTestNativeWidget() override {
511 state_->native_widget_deleted = true;
514 private:
515 OwnershipTestState* state_;
517 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
520 // A views NativeWidget subclass that updates a bag of state when it is
521 // destroyed.
522 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
523 public:
524 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
525 OwnershipTestState* state)
526 : NativeWidgetCapture(delegate),
527 state_(state) {
529 ~OwnershipTestNativeWidgetAura() override {
530 state_->native_widget_deleted = true;
533 private:
534 OwnershipTestState* state_;
536 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
539 // A Widget subclass that updates a bag of state when it is destroyed.
540 class OwnershipTestWidget : public Widget {
541 public:
542 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
543 ~OwnershipTestWidget() override { state_->widget_deleted = true; }
545 private:
546 OwnershipTestState* state_;
548 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
551 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
552 // widget.
553 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
554 OwnershipTestState state;
556 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
557 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
558 params.native_widget =
559 new OwnershipTestNativeWidgetAura(widget.get(), &state);
560 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
561 widget->Init(params);
563 // Now delete the Widget, which should delete the NativeWidget.
564 widget.reset();
566 EXPECT_TRUE(state.widget_deleted);
567 EXPECT_TRUE(state.native_widget_deleted);
569 // TODO(beng): write test for this ownership scenario and the NativeWidget
570 // being deleted out from under the Widget.
573 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
574 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
575 OwnershipTestState state;
577 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
578 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
579 params.native_widget =
580 new OwnershipTestNativeWidgetAura(widget.get(), &state);
581 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
582 widget->Init(params);
584 // Now delete the Widget, which should delete the NativeWidget.
585 widget.reset();
587 EXPECT_TRUE(state.widget_deleted);
588 EXPECT_TRUE(state.native_widget_deleted);
590 // TODO(beng): write test for this ownership scenario and the NativeWidget
591 // being deleted out from under the Widget.
594 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
595 // destroy the parent view.
596 TEST_F(WidgetOwnershipTest,
597 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
598 OwnershipTestState state;
600 Widget* toplevel = CreateTopLevelPlatformWidget();
602 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
603 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
604 params.native_widget =
605 new OwnershipTestNativeWidgetAura(widget.get(), &state);
606 params.parent = toplevel->GetNativeView();
607 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
608 widget->Init(params);
610 // Now close the toplevel, which deletes the view hierarchy.
611 toplevel->CloseNow();
613 RunPendingMessages();
615 // This shouldn't delete the widget because it shouldn't be deleted
616 // from the native side.
617 EXPECT_FALSE(state.widget_deleted);
618 EXPECT_FALSE(state.native_widget_deleted);
620 // Now delete it explicitly.
621 widget.reset();
623 EXPECT_TRUE(state.widget_deleted);
624 EXPECT_TRUE(state.native_widget_deleted);
627 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
628 // widget.
629 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
630 OwnershipTestState state;
632 Widget* widget = new OwnershipTestWidget(&state);
633 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
634 params.native_widget =
635 new OwnershipTestNativeWidgetAura(widget, &state);
636 widget->Init(params);
638 // Now destroy the native widget.
639 widget->CloseNow();
641 EXPECT_TRUE(state.widget_deleted);
642 EXPECT_TRUE(state.native_widget_deleted);
645 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
646 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
647 OwnershipTestState state;
649 Widget* toplevel = CreateTopLevelPlatformWidget();
651 Widget* widget = new OwnershipTestWidget(&state);
652 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
653 params.native_widget =
654 new OwnershipTestNativeWidgetAura(widget, &state);
655 params.parent = toplevel->GetNativeView();
656 widget->Init(params);
658 // Now destroy the native widget. This is achieved by closing the toplevel.
659 toplevel->CloseNow();
661 // The NativeWidget won't be deleted until after a return to the message loop
662 // so we have to run pending messages before testing the destruction status.
663 RunPendingMessages();
665 EXPECT_TRUE(state.widget_deleted);
666 EXPECT_TRUE(state.native_widget_deleted);
669 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
670 // widget, destroyed out from under it by the OS.
671 TEST_F(WidgetOwnershipTest,
672 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
673 OwnershipTestState state;
675 Widget* widget = new OwnershipTestWidget(&state);
676 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
677 params.native_widget =
678 new OwnershipTestNativeWidgetAura(widget, &state);
679 widget->Init(params);
681 // Now simulate a destroy of the platform native widget from the OS:
682 SimulateNativeDestroy(widget);
684 EXPECT_TRUE(state.widget_deleted);
685 EXPECT_TRUE(state.native_widget_deleted);
688 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
689 // destroyed by the view hierarchy that contains it.
690 TEST_F(WidgetOwnershipTest,
691 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
692 OwnershipTestState state;
694 Widget* toplevel = CreateTopLevelPlatformWidget();
696 Widget* widget = new OwnershipTestWidget(&state);
697 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
698 params.native_widget =
699 new OwnershipTestNativeWidgetAura(widget, &state);
700 params.parent = toplevel->GetNativeView();
701 widget->Init(params);
703 // Destroy the widget (achieved by closing the toplevel).
704 toplevel->CloseNow();
706 // The NativeWidget won't be deleted until after a return to the message loop
707 // so we have to run pending messages before testing the destruction status.
708 RunPendingMessages();
710 EXPECT_TRUE(state.widget_deleted);
711 EXPECT_TRUE(state.native_widget_deleted);
714 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
715 // we close it directly.
716 TEST_F(WidgetOwnershipTest,
717 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
718 OwnershipTestState state;
720 Widget* toplevel = CreateTopLevelPlatformWidget();
722 Widget* widget = new OwnershipTestWidget(&state);
723 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
724 params.native_widget =
725 new OwnershipTestNativeWidgetAura(widget, &state);
726 params.parent = toplevel->GetNativeView();
727 widget->Init(params);
729 // Destroy the widget.
730 widget->Close();
731 toplevel->CloseNow();
733 // The NativeWidget won't be deleted until after a return to the message loop
734 // so we have to run pending messages before testing the destruction status.
735 RunPendingMessages();
737 EXPECT_TRUE(state.widget_deleted);
738 EXPECT_TRUE(state.native_widget_deleted);
741 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
742 TEST_F(WidgetOwnershipTest,
743 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
744 OwnershipTestState state;
746 WidgetDelegateView* delegate_view = new WidgetDelegateView;
748 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
749 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
750 params.native_widget =
751 new OwnershipTestNativeWidgetAura(widget.get(), &state);
752 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
753 params.delegate = delegate_view;
754 widget->Init(params);
755 widget->SetContentsView(delegate_view);
757 // Now delete the Widget. There should be no crash or use-after-free.
758 widget.reset();
760 EXPECT_TRUE(state.widget_deleted);
761 EXPECT_TRUE(state.native_widget_deleted);
764 ////////////////////////////////////////////////////////////////////////////////
765 // Test to verify using various Widget methods doesn't crash when the underlying
766 // NativeView is destroyed.
768 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
769 public:
770 WidgetWithDestroyedNativeViewTest() {}
771 ~WidgetWithDestroyedNativeViewTest() override {}
773 void InvokeWidgetMethods(Widget* widget) {
774 widget->GetNativeView();
775 widget->GetNativeWindow();
776 ui::Accelerator accelerator;
777 widget->GetAccelerator(0, &accelerator);
778 widget->GetTopLevelWidget();
779 widget->GetWindowBoundsInScreen();
780 widget->GetClientAreaBoundsInScreen();
781 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
782 widget->SetSize(gfx::Size(10, 11));
783 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
784 widget->SetVisibilityChangedAnimationsEnabled(false);
785 widget->StackAtTop();
786 widget->IsClosed();
787 widget->Close();
788 widget->Hide();
789 widget->Activate();
790 widget->Deactivate();
791 widget->IsActive();
792 widget->DisableInactiveRendering();
793 widget->SetAlwaysOnTop(true);
794 widget->IsAlwaysOnTop();
795 widget->Maximize();
796 widget->Minimize();
797 widget->Restore();
798 widget->IsMaximized();
799 widget->IsFullscreen();
800 widget->SetOpacity(0);
801 widget->SetUseDragFrame(true);
802 widget->FlashFrame(true);
803 widget->IsVisible();
804 widget->GetThemeProvider();
805 widget->GetNativeTheme();
806 widget->GetFocusManager();
807 widget->GetInputMethod();
808 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
809 widget->IsMouseEventsEnabled();
810 widget->SetNativeWindowProperty("xx", widget);
811 widget->GetNativeWindowProperty("xx");
812 widget->GetFocusTraversable();
813 widget->GetLayer();
814 widget->ReorderNativeViews();
815 widget->SetCapture(widget->GetRootView());
816 widget->ReleaseCapture();
817 widget->HasCapture();
818 widget->GetWorkAreaBoundsInScreen();
819 widget->IsTranslucentWindowOpacitySupported();
822 private:
823 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
826 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
828 Widget widget;
829 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
830 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
831 widget.Init(params);
832 widget.Show();
834 widget.native_widget_private()->CloseNow();
835 InvokeWidgetMethods(&widget);
837 #if !defined(OS_CHROMEOS)
839 Widget widget;
840 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
841 params.native_widget = new PlatformDesktopNativeWidget(&widget);
842 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
843 widget.Init(params);
844 widget.Show();
846 widget.native_widget_private()->CloseNow();
847 InvokeWidgetMethods(&widget);
849 #endif
852 ////////////////////////////////////////////////////////////////////////////////
853 // Widget observer tests.
856 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
857 public:
858 WidgetObserverTest()
859 : active_(nullptr),
860 widget_closed_(nullptr),
861 widget_activated_(nullptr),
862 widget_shown_(nullptr),
863 widget_hidden_(nullptr),
864 widget_bounds_changed_(nullptr),
865 widget_to_close_on_hide_(nullptr) {
868 ~WidgetObserverTest() override {}
870 // Set a widget to Close() the next time the Widget being observed is hidden.
871 void CloseOnNextHide(Widget* widget) {
872 widget_to_close_on_hide_ = widget;
875 // Overridden from WidgetObserver:
876 void OnWidgetDestroying(Widget* widget) override {
877 if (active_ == widget)
878 active_ = nullptr;
879 widget_closed_ = widget;
882 void OnWidgetActivationChanged(Widget* widget, bool active) override {
883 if (active) {
884 if (widget_activated_)
885 widget_activated_->Deactivate();
886 widget_activated_ = widget;
887 active_ = widget;
888 } else {
889 if (widget_activated_ == widget)
890 widget_activated_ = nullptr;
891 widget_deactivated_ = widget;
895 void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
896 if (visible) {
897 widget_shown_ = widget;
898 return;
900 widget_hidden_ = widget;
901 if (widget_to_close_on_hide_) {
902 widget_to_close_on_hide_->Close();
903 widget_to_close_on_hide_ = nullptr;
907 void OnWidgetBoundsChanged(Widget* widget,
908 const gfx::Rect& new_bounds) override {
909 widget_bounds_changed_ = widget;
912 void reset() {
913 active_ = nullptr;
914 widget_closed_ = nullptr;
915 widget_activated_ = nullptr;
916 widget_deactivated_ = nullptr;
917 widget_shown_ = nullptr;
918 widget_hidden_ = nullptr;
919 widget_bounds_changed_ = nullptr;
922 Widget* NewWidget() {
923 Widget* widget = CreateTopLevelNativeWidget();
924 widget->AddObserver(this);
925 return widget;
928 const Widget* active() const { return active_; }
929 const Widget* widget_closed() const { return widget_closed_; }
930 const Widget* widget_activated() const { return widget_activated_; }
931 const Widget* widget_deactivated() const { return widget_deactivated_; }
932 const Widget* widget_shown() const { return widget_shown_; }
933 const Widget* widget_hidden() const { return widget_hidden_; }
934 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
936 private:
937 Widget* active_;
939 Widget* widget_closed_;
940 Widget* widget_activated_;
941 Widget* widget_deactivated_;
942 Widget* widget_shown_;
943 Widget* widget_hidden_;
944 Widget* widget_bounds_changed_;
946 Widget* widget_to_close_on_hide_;
949 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
950 Widget* toplevel = CreateTopLevelPlatformWidget();
952 Widget* toplevel1 = NewWidget();
953 Widget* toplevel2 = NewWidget();
955 toplevel1->Show();
956 toplevel2->Show();
958 reset();
960 toplevel1->Activate();
962 RunPendingMessages();
963 EXPECT_EQ(toplevel1, widget_activated());
965 toplevel2->Activate();
966 RunPendingMessages();
967 EXPECT_EQ(toplevel1, widget_deactivated());
968 EXPECT_EQ(toplevel2, widget_activated());
969 EXPECT_EQ(toplevel2, active());
971 toplevel->CloseNow();
974 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
975 Widget* toplevel = CreateTopLevelPlatformWidget();
977 Widget* child1 = NewWidget();
978 Widget* child2 = NewWidget();
980 toplevel->Show();
981 child1->Show();
982 child2->Show();
984 reset();
986 child1->Hide();
987 EXPECT_EQ(child1, widget_hidden());
989 child2->Hide();
990 EXPECT_EQ(child2, widget_hidden());
992 child1->Show();
993 EXPECT_EQ(child1, widget_shown());
995 child2->Show();
996 EXPECT_EQ(child2, widget_shown());
998 toplevel->CloseNow();
1001 TEST_F(WidgetObserverTest, DestroyBubble) {
1002 Widget* anchor = CreateTopLevelPlatformWidget();
1003 anchor->Show();
1005 BubbleDelegateView* bubble_delegate =
1006 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
1007 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1008 bubble_widget->Show();
1009 bubble_widget->CloseNow();
1011 anchor->Hide();
1012 anchor->CloseNow();
1015 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
1016 Widget* child1 = NewWidget();
1017 Widget* child2 = NewWidget();
1019 child1->OnNativeWidgetMove();
1020 EXPECT_EQ(child1, widget_bounds_changed());
1022 child2->OnNativeWidgetMove();
1023 EXPECT_EQ(child2, widget_bounds_changed());
1025 child1->OnNativeWidgetSizeChanged(gfx::Size());
1026 EXPECT_EQ(child1, widget_bounds_changed());
1028 child2->OnNativeWidgetSizeChanged(gfx::Size());
1029 EXPECT_EQ(child2, widget_bounds_changed());
1032 // An extension to WidgetBoundsChanged to ensure notifications are forwarded
1033 // by the NativeWidget implementation.
1034 TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
1035 // Don't use NewWidget(), so that the Init() flow can be observed to ensure
1036 // consistency across platforms.
1037 Widget* widget = new Widget(); // Note: owned by NativeWidget.
1038 widget->AddObserver(this);
1040 EXPECT_FALSE(widget_bounds_changed());
1042 // Init causes a bounds change, even while not showing. Note some platforms
1043 // cause a bounds change even when the bounds are empty. Mac does not.
1044 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
1045 params.bounds = gfx::Rect(0, 0, 100, 100);
1046 widget->Init(params);
1047 EXPECT_TRUE(widget_bounds_changed());
1048 reset();
1050 // Resizing while hidden, triggers a change.
1051 widget->SetSize(gfx::Size(160, 100));
1052 EXPECT_FALSE(widget->IsVisible());
1053 EXPECT_TRUE(widget_bounds_changed());
1054 reset();
1056 // Setting the same size does nothing.
1057 widget->SetSize(gfx::Size(160, 100));
1058 EXPECT_FALSE(widget_bounds_changed());
1059 reset();
1061 // Showing does nothing to the bounds.
1062 widget->Show();
1063 EXPECT_TRUE(widget->IsVisible());
1064 EXPECT_FALSE(widget_bounds_changed());
1065 reset();
1067 // Resizing while shown.
1068 widget->SetSize(gfx::Size(170, 100));
1069 EXPECT_TRUE(widget_bounds_changed());
1070 reset();
1072 // Resize to the same thing while shown does nothing.
1073 widget->SetSize(gfx::Size(170, 100));
1074 EXPECT_FALSE(widget_bounds_changed());
1075 reset();
1077 // No bounds change when closing.
1078 widget->CloseNow();
1079 EXPECT_FALSE(widget_bounds_changed());
1082 // Test correct behavior when widgets close themselves in response to visibility
1083 // changes.
1084 TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
1085 Widget* parent = NewWidget();
1086 Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
1088 TestWidgetObserver child_observer(child);
1090 EXPECT_FALSE(parent->IsVisible());
1091 EXPECT_FALSE(child->IsVisible());
1093 // Note |child| is TYPE_CONTROL, which start shown. So no need to show the
1094 // child separately.
1095 parent->Show();
1096 EXPECT_TRUE(parent->IsVisible());
1097 EXPECT_TRUE(child->IsVisible());
1099 // Simulate a child widget that closes itself when the parent is hidden.
1100 CloseOnNextHide(child);
1101 EXPECT_FALSE(child_observer.widget_closed());
1102 parent->Hide();
1103 RunPendingMessages();
1104 EXPECT_TRUE(child_observer.widget_closed());
1106 parent->CloseNow();
1109 // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop.
1110 TEST_F(WidgetTest, GetWindowPlacement) {
1111 Widget* widget;
1112 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1113 // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is
1114 // asynchronous. Also (harder) showing a window doesn't activate it without
1115 // user interaction (or extra steps only done for interactive ui tests).
1116 // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout.
1117 // TODO(tapted): Find a nice way to run this with desktop widgets on Linux.
1118 widget = CreateTopLevelPlatformWidget();
1119 #else
1120 widget = CreateNativeDesktopWidget();
1121 #endif
1123 gfx::Rect expected_bounds(100, 110, 200, 220);
1124 widget->SetBounds(expected_bounds);
1125 widget->Show();
1127 // Start with something invalid to ensure it changes.
1128 ui::WindowShowState show_state = ui::SHOW_STATE_END;
1129 gfx::Rect restored_bounds;
1131 internal::NativeWidgetPrivate* native_widget =
1132 widget->native_widget_private();
1134 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1135 EXPECT_EQ(expected_bounds, restored_bounds);
1136 #if defined(OS_LINUX)
1137 // Non-desktop/Ash widgets start off in "default" until a Restore().
1138 EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
1139 widget->Restore();
1140 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1141 #endif
1142 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1144 widget->Minimize();
1145 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1146 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, show_state);
1147 EXPECT_EQ(expected_bounds, restored_bounds);
1149 widget->Restore();
1150 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1151 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1152 EXPECT_EQ(expected_bounds, restored_bounds);
1154 expected_bounds = gfx::Rect(130, 140, 230, 250);
1155 widget->SetBounds(expected_bounds);
1156 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1157 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1158 EXPECT_EQ(expected_bounds, restored_bounds);
1160 widget->SetFullscreen(true);
1161 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1163 #if defined(OS_WIN)
1164 // Desktop Aura widgets on Windows currently don't update show_state when
1165 // going fullscreen, and report restored_bounds as the full screen size.
1166 // See http://crbug.com/475813.
1167 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1168 #else
1169 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, show_state);
1170 EXPECT_EQ(expected_bounds, restored_bounds);
1171 #endif
1173 widget->SetFullscreen(false);
1174 native_widget->GetWindowPlacement(&restored_bounds, &show_state);
1175 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
1176 EXPECT_EQ(expected_bounds, restored_bounds);
1178 widget->CloseNow();
1181 // Test that widget size constraints are properly applied immediately after
1182 // Init(), and that SetBounds() calls are appropriately clamped.
1183 TEST_F(WidgetTest, MinimumSizeConstraints) {
1184 TestDesktopWidgetDelegate delegate;
1185 gfx::Size minimum_size(100, 100);
1186 const gfx::Size smaller_size(90, 90);
1188 delegate.set_contents_view(new StaticSizedView(minimum_size));
1189 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1190 Widget* widget = delegate.GetWidget();
1192 // On desktop Linux, the Widget must be shown to ensure the window is mapped.
1193 // On other platforms this line is optional.
1194 widget->Show();
1196 // Sanity checks.
1197 EXPECT_GT(delegate.initial_bounds().width(), minimum_size.width());
1198 EXPECT_GT(delegate.initial_bounds().height(), minimum_size.height());
1199 EXPECT_EQ(delegate.initial_bounds().size(),
1200 widget->GetWindowBoundsInScreen().size());
1201 // Note: StaticSizedView doesn't currently provide a maximum size.
1202 EXPECT_EQ(gfx::Size(), widget->GetMaximumSize());
1204 if (!widget->ShouldUseNativeFrame()) {
1205 // The test environment may have dwm disabled on Windows. In this case,
1206 // CustomFrameView is used instead of the NativeFrameView, which will
1207 // provide a minimum size that includes frame decorations.
1208 minimum_size = widget->non_client_view()->GetWindowBoundsForClientBounds(
1209 gfx::Rect(minimum_size)).size();
1212 EXPECT_EQ(minimum_size, widget->GetMinimumSize());
1213 EXPECT_EQ(minimum_size, GetNativeWidgetMinimumContentSize(widget));
1215 // Trying to resize smaller than the minimum size should restrict the content
1216 // size to the minimum size.
1217 widget->SetBounds(gfx::Rect(smaller_size));
1218 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1220 widget->SetSize(smaller_size);
1221 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1222 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it.
1223 EXPECT_EQ(smaller_size, widget->GetClientAreaBoundsInScreen().size());
1224 #else
1225 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
1226 #endif
1229 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
1230 // widget is visible and not maximized or fullscreen.
1231 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
1232 // Choose test coordinates away from edges and dimensions that are "small"
1233 // (but not too small) to ensure the OS doesn't try to adjust them.
1234 const gfx::Rect kTestBounds(150, 150, 400, 300);
1235 const gfx::Size kTestSize(200, 180);
1237 // First test a toplevel widget.
1238 Widget* widget = CreateTopLevelPlatformWidget();
1239 widget->Show();
1241 EXPECT_NE(kTestSize.ToString(),
1242 widget->GetWindowBoundsInScreen().size().ToString());
1243 widget->SetSize(kTestSize);
1244 EXPECT_EQ(kTestSize.ToString(),
1245 widget->GetWindowBoundsInScreen().size().ToString());
1247 EXPECT_NE(kTestBounds.ToString(),
1248 widget->GetWindowBoundsInScreen().ToString());
1249 widget->SetBounds(kTestBounds);
1250 EXPECT_EQ(kTestBounds.ToString(),
1251 widget->GetWindowBoundsInScreen().ToString());
1253 // Changing just the size should not change the origin.
1254 widget->SetSize(kTestSize);
1255 EXPECT_EQ(kTestBounds.origin().ToString(),
1256 widget->GetWindowBoundsInScreen().origin().ToString());
1258 widget->CloseNow();
1260 // Same tests with a frameless window.
1261 widget = CreateTopLevelFramelessPlatformWidget();
1262 widget->Show();
1264 EXPECT_NE(kTestSize.ToString(),
1265 widget->GetWindowBoundsInScreen().size().ToString());
1266 widget->SetSize(kTestSize);
1267 EXPECT_EQ(kTestSize.ToString(),
1268 widget->GetWindowBoundsInScreen().size().ToString());
1270 EXPECT_NE(kTestBounds.ToString(),
1271 widget->GetWindowBoundsInScreen().ToString());
1272 widget->SetBounds(kTestBounds);
1273 EXPECT_EQ(kTestBounds.ToString(),
1274 widget->GetWindowBoundsInScreen().ToString());
1276 // For a frameless widget, the client bounds should also match.
1277 EXPECT_EQ(kTestBounds.ToString(),
1278 widget->GetClientAreaBoundsInScreen().ToString());
1280 // Verify origin is stable for a frameless window as well.
1281 widget->SetSize(kTestSize);
1282 EXPECT_EQ(kTestBounds.origin().ToString(),
1283 widget->GetWindowBoundsInScreen().origin().ToString());
1285 widget->CloseNow();
1288 // Before being enabled on Mac, this was #ifdef(false).
1289 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
1290 #if defined(OS_MACOSX)
1291 // Aura needs shell to maximize/fullscreen window.
1292 // NativeWidgetGtk doesn't implement GetRestoredBounds.
1293 TEST_F(WidgetTest, GetRestoredBounds) {
1294 Widget* toplevel = CreateTopLevelPlatformWidget();
1295 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1296 toplevel->GetRestoredBounds().ToString());
1297 toplevel->Show();
1298 toplevel->Maximize();
1299 RunPendingMessages();
1300 #if defined(OS_MACOSX)
1301 // Current expectation on Mac is to do nothing on Maximize.
1302 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1303 toplevel->GetRestoredBounds().ToString());
1304 #else
1305 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1306 toplevel->GetRestoredBounds().ToString());
1307 #endif
1308 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1309 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1311 toplevel->Restore();
1312 RunPendingMessages();
1313 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1314 toplevel->GetRestoredBounds().ToString());
1316 toplevel->SetFullscreen(true);
1317 RunPendingMessages();
1319 if (IsTestingSnowLeopard()) {
1320 // Fullscreen not implemented for Snow Leopard.
1321 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
1322 toplevel->GetRestoredBounds().ToString());
1323 } else {
1324 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
1325 toplevel->GetRestoredBounds().ToString());
1327 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
1328 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
1330 #endif
1332 // The key-event propagation from Widget happens differently on aura and
1333 // non-aura systems because of the difference in IME. So this test works only on
1334 // aura.
1335 TEST_F(WidgetTest, KeyboardInputEvent) {
1336 Widget* toplevel = CreateTopLevelPlatformWidget();
1337 View* container = toplevel->client_view();
1339 Textfield* textfield = new Textfield();
1340 textfield->SetText(base::ASCIIToUTF16("some text"));
1341 container->AddChildView(textfield);
1342 toplevel->Show();
1343 textfield->RequestFocus();
1345 // The press gets handled. The release doesn't have an effect.
1346 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1347 toplevel->OnKeyEvent(&backspace_p);
1348 EXPECT_TRUE(backspace_p.stopped_propagation());
1349 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1350 toplevel->OnKeyEvent(&backspace_r);
1351 EXPECT_FALSE(backspace_r.handled());
1353 toplevel->Close();
1356 // Verifies bubbles result in a focus lost when shown.
1357 // TODO(msw): this tests relies on focus, it needs to be in
1358 // interactive_ui_tests.
1359 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1360 // Create a widget, show and activate it and focus the contents view.
1361 View* contents_view = new View;
1362 contents_view->SetFocusable(true);
1363 Widget widget;
1364 Widget::InitParams init_params =
1365 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1366 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1367 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1368 #if !defined(OS_CHROMEOS)
1369 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1370 #endif
1371 widget.Init(init_params);
1372 widget.SetContentsView(contents_view);
1373 widget.Show();
1374 widget.Activate();
1375 contents_view->RequestFocus();
1376 EXPECT_TRUE(contents_view->HasFocus());
1378 // Show a bubble.
1379 BubbleDelegateView* bubble_delegate_view =
1380 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1381 bubble_delegate_view->SetFocusable(true);
1382 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1383 bubble_delegate_view->RequestFocus();
1385 // |contents_view_| should no longer have focus.
1386 EXPECT_FALSE(contents_view->HasFocus());
1387 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1389 bubble_delegate_view->GetWidget()->CloseNow();
1391 // Closing the bubble should result in focus going back to the contents view.
1392 EXPECT_TRUE(contents_view->HasFocus());
1395 class TestBubbleDelegateView : public BubbleDelegateView {
1396 public:
1397 TestBubbleDelegateView(View* anchor)
1398 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1399 reset_controls_called_(false) {}
1400 ~TestBubbleDelegateView() override {}
1402 bool ShouldShowCloseButton() const override {
1403 reset_controls_called_ = true;
1404 return true;
1407 mutable bool reset_controls_called_;
1410 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1411 Widget* anchor = CreateTopLevelPlatformWidget();
1412 anchor->Show();
1414 TestBubbleDelegateView* bubble_delegate =
1415 new TestBubbleDelegateView(anchor->client_view());
1416 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1417 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1418 bubble_widget->Show();
1419 bubble_widget->CloseNow();
1421 anchor->Hide();
1422 anchor->CloseNow();
1425 #if defined(OS_WIN)
1426 // Test to ensure that after minimize, view width is set to zero. This is only
1427 // the case for desktop widgets on Windows. Other platforms retain the window
1428 // size while minimized.
1429 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1430 // Create a widget.
1431 Widget widget;
1432 Widget::InitParams init_params =
1433 CreateParams(Widget::InitParams::TYPE_WINDOW);
1434 init_params.show_state = ui::SHOW_STATE_NORMAL;
1435 gfx::Rect initial_bounds(0, 0, 300, 400);
1436 init_params.bounds = initial_bounds;
1437 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1438 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1439 widget.Init(init_params);
1440 NonClientView* non_client_view = widget.non_client_view();
1441 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1442 non_client_view->SetFrameView(frame_view);
1443 // Setting the frame view doesn't do a layout, so force one.
1444 non_client_view->Layout();
1445 widget.Show();
1446 EXPECT_NE(0, frame_view->width());
1447 widget.Minimize();
1448 EXPECT_EQ(0, frame_view->width());
1450 #endif
1452 // Desktop native widget Aura tests are for non Chrome OS platforms.
1453 #if !defined(OS_CHROMEOS)
1454 // This class validates whether paints are received for a visible Widget.
1455 // To achieve this it overrides the Show and Close methods on the Widget class
1456 // and sets state whether subsequent paints are expected.
1457 class DesktopAuraTestValidPaintWidget : public views::Widget {
1458 public:
1459 DesktopAuraTestValidPaintWidget()
1460 : received_paint_(false),
1461 expect_paint_(true),
1462 received_paint_while_hidden_(false) {}
1464 ~DesktopAuraTestValidPaintWidget() override {}
1466 void InitForTest(Widget::InitParams create_params);
1468 void Show() override {
1469 expect_paint_ = true;
1470 views::Widget::Show();
1473 void Close() override {
1474 expect_paint_ = false;
1475 views::Widget::Close();
1478 void Hide() {
1479 expect_paint_ = false;
1480 views::Widget::Hide();
1483 void OnNativeWidgetPaint(const ui::PaintContext& context) override {
1484 received_paint_ = true;
1485 EXPECT_TRUE(expect_paint_);
1486 if (!expect_paint_)
1487 received_paint_while_hidden_ = true;
1488 views::Widget::OnNativeWidgetPaint(context);
1491 bool ReadReceivedPaintAndReset() {
1492 bool result = received_paint_;
1493 received_paint_ = false;
1494 return result;
1497 bool received_paint_while_hidden() const {
1498 return received_paint_while_hidden_;
1501 private:
1502 bool received_paint_;
1503 bool expect_paint_;
1504 bool received_paint_while_hidden_;
1506 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1509 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1510 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1511 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1512 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1513 Init(init_params);
1515 View* contents_view = new View;
1516 contents_view->SetFocusable(true);
1517 SetContentsView(contents_view);
1519 Show();
1520 Activate();
1523 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1524 DesktopAuraTestValidPaintWidget widget;
1525 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1526 RunPendingMessages();
1527 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1528 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1529 widget.Close();
1530 RunPendingMessages();
1531 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1532 EXPECT_FALSE(widget.received_paint_while_hidden());
1535 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1536 DesktopAuraTestValidPaintWidget widget;
1537 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1538 RunPendingMessages();
1539 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1540 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1541 widget.Hide();
1542 RunPendingMessages();
1543 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1544 EXPECT_FALSE(widget.received_paint_while_hidden());
1545 widget.Close();
1548 // Test to ensure that the aura Window's visiblity state is set to visible if
1549 // the underlying widget is hidden and then shown.
1550 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1551 // Create a widget.
1552 Widget widget;
1553 Widget::InitParams init_params =
1554 CreateParams(Widget::InitParams::TYPE_WINDOW);
1555 init_params.show_state = ui::SHOW_STATE_NORMAL;
1556 gfx::Rect initial_bounds(0, 0, 300, 400);
1557 init_params.bounds = initial_bounds;
1558 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1559 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1560 widget.Init(init_params);
1561 NonClientView* non_client_view = widget.non_client_view();
1562 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1563 non_client_view->SetFrameView(frame_view);
1565 widget.Show();
1566 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1567 widget.Hide();
1568 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1569 widget.Show();
1570 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1573 #endif // !defined(OS_CHROMEOS)
1575 // Tests that wheel events generated from scroll events are targetted to the
1576 // views under the cursor when the focused view does not processed them.
1577 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1578 EventCountView* cursor_view = new EventCountView;
1579 cursor_view->SetBounds(60, 0, 50, 40);
1581 Widget* widget = CreateTopLevelPlatformWidget();
1582 widget->GetRootView()->AddChildView(cursor_view);
1584 // Generate a scroll event on the cursor view.
1585 ui::ScrollEvent scroll(ui::ET_SCROLL,
1586 gfx::Point(65, 5),
1587 ui::EventTimeForNow(),
1589 0, 20,
1590 0, 20,
1592 widget->OnScrollEvent(&scroll);
1594 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1595 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1597 cursor_view->ResetCounts();
1599 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1600 gfx::Point(5, 5),
1601 ui::EventTimeForNow(),
1603 0, 20,
1604 0, 20,
1606 widget->OnScrollEvent(&scroll2);
1608 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1609 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1611 widget->CloseNow();
1614 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1615 // events are not dispatched to any view.
1616 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1617 EventCountView* noscroll_view = new EventCountView;
1618 EventCountView* scroll_view = new ScrollableEventCountView;
1620 noscroll_view->SetBounds(0, 0, 50, 40);
1621 scroll_view->SetBounds(60, 0, 40, 40);
1623 Widget* widget = CreateTopLevelPlatformWidget();
1624 widget->GetRootView()->AddChildView(noscroll_view);
1625 widget->GetRootView()->AddChildView(scroll_view);
1628 ui::GestureEvent begin(
1632 base::TimeDelta(),
1633 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1634 widget->OnGestureEvent(&begin);
1635 ui::GestureEvent update(
1639 base::TimeDelta(),
1640 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1641 widget->OnGestureEvent(&update);
1642 ui::GestureEvent end(25,
1645 base::TimeDelta(),
1646 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1647 widget->OnGestureEvent(&end);
1649 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1650 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1651 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1655 ui::GestureEvent begin(
1659 base::TimeDelta(),
1660 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1661 widget->OnGestureEvent(&begin);
1662 ui::GestureEvent update(
1666 base::TimeDelta(),
1667 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1668 widget->OnGestureEvent(&update);
1669 ui::GestureEvent end(85,
1672 base::TimeDelta(),
1673 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1674 widget->OnGestureEvent(&end);
1676 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1677 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1678 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1681 widget->CloseNow();
1684 // Tests that event-handlers installed on the RootView get triggered correctly.
1685 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1686 TEST_F(WidgetTest, EventHandlersOnRootView) {
1687 Widget* widget = CreateTopLevelNativeWidget();
1688 View* root_view = widget->GetRootView();
1690 scoped_ptr<EventCountView> view(new EventCountView());
1691 view->set_owned_by_client();
1692 view->SetBounds(0, 0, 20, 20);
1693 root_view->AddChildView(view.get());
1695 EventCountHandler h1;
1696 root_view->AddPreTargetHandler(&h1);
1698 EventCountHandler h2;
1699 root_view->AddPostTargetHandler(&h2);
1701 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1702 widget->Show();
1704 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1705 // bubble up the views hierarchy to be re-dispatched on the root view.
1706 ui::ScrollEvent scroll(ui::ET_SCROLL,
1707 gfx::Point(5, 5),
1708 ui::EventTimeForNow(),
1710 0, 20,
1711 0, 20,
1713 widget->OnScrollEvent(&scroll);
1714 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1715 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1716 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1718 // Unhandled scroll events are turned into wheel events and re-dispatched.
1719 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1720 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1721 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1723 h1.ResetCounts();
1724 view->ResetCounts();
1725 h2.ResetCounts();
1727 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1728 // should bubble up the views hierarchy to be re-dispatched on the root view.
1729 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1730 gfx::Point(5, 5),
1731 ui::EventTimeForNow(),
1733 0, 20,
1734 0, 20,
1736 widget->OnScrollEvent(&fling);
1737 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1738 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1739 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1741 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1742 // be turned into wheel events and re-dispatched.
1743 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1744 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1745 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1747 h1.ResetCounts();
1748 view->ResetCounts();
1749 h2.ResetCounts();
1751 // Change the handle mode of |view| so that events are marked as handled at
1752 // the target phase.
1753 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1755 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1756 // The events are handled at the target phase and should not reach the
1757 // post-target handler.
1758 ui::GestureEvent tap_down(5,
1761 ui::EventTimeForNow(),
1762 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1763 widget->OnGestureEvent(&tap_down);
1764 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1765 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1766 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1768 ui::GestureEvent tap_cancel(
1772 ui::EventTimeForNow(),
1773 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1774 widget->OnGestureEvent(&tap_cancel);
1775 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1776 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1777 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1779 h1.ResetCounts();
1780 view->ResetCounts();
1781 h2.ResetCounts();
1783 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1784 // and should not reach the post-target handler.
1785 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1786 gfx::Point(5, 5),
1787 ui::EventTimeForNow(),
1789 0, 20,
1790 0, 20,
1792 widget->OnScrollEvent(&consumed_scroll);
1793 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1794 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1795 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1797 // Handled scroll events are not turned into wheel events and re-dispatched.
1798 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1799 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1800 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1802 widget->CloseNow();
1805 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1806 Widget* widget = CreateTopLevelNativeWidget();
1807 View* root_view = widget->GetRootView();
1809 EventCountView* v1 = new EventCountView();
1810 v1->SetBounds(0, 0, 10, 10);
1811 root_view->AddChildView(v1);
1812 EventCountView* v2 = new EventCountView();
1813 v2->SetBounds(0, 10, 10, 10);
1814 root_view->AddChildView(v2);
1816 gfx::Point cursor_location(5, 5);
1817 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1818 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
1819 widget->OnMouseEvent(&move);
1821 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1822 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1824 delete v1;
1825 v2->SetBounds(0, 0, 10, 10);
1826 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1828 widget->SynthesizeMouseMoveEvent();
1829 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1832 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1833 #if !defined(OS_MACOSX) || defined(USE_AURA)
1835 namespace {
1837 // ui::EventHandler which handles all mouse press events.
1838 class MousePressEventConsumer : public ui::EventHandler {
1839 public:
1840 MousePressEventConsumer() {}
1842 private:
1843 // ui::EventHandler:
1844 void OnMouseEvent(ui::MouseEvent* event) override {
1845 if (event->type() == ui::ET_MOUSE_PRESSED)
1846 event->SetHandled();
1849 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1852 } // namespace
1854 // Test that mouse presses and mouse releases are dispatched normally when a
1855 // touch is down.
1856 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1857 Widget* widget = CreateTopLevelNativeWidget();
1858 widget->Show();
1859 widget->SetSize(gfx::Size(300, 300));
1861 EventCountView* event_count_view = new EventCountView();
1862 event_count_view->SetBounds(0, 0, 300, 300);
1863 widget->GetRootView()->AddChildView(event_count_view);
1865 MousePressEventConsumer consumer;
1866 event_count_view->AddPostTargetHandler(&consumer);
1868 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1869 generator.PressTouch();
1870 generator.ClickLeftButton();
1872 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1873 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1875 widget->CloseNow();
1878 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1880 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1881 // is closed.
1882 TEST_F(WidgetTest, SingleWindowClosing) {
1883 TestDesktopWidgetDelegate delegate;
1884 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
1885 EXPECT_EQ(0, delegate.window_closing_count());
1886 delegate.GetWidget()->CloseNow();
1887 EXPECT_EQ(1, delegate.window_closing_count());
1890 class WidgetWindowTitleTest : public WidgetTest {
1891 protected:
1892 void RunTest(bool desktop_native_widget) {
1893 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1894 Widget::InitParams init_params =
1895 CreateParams(Widget::InitParams::TYPE_WINDOW);
1896 widget->Init(init_params);
1898 #if !defined(OS_CHROMEOS)
1899 if (desktop_native_widget)
1900 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1901 #else
1902 DCHECK(!desktop_native_widget)
1903 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1904 #endif
1906 internal::NativeWidgetPrivate* native_widget =
1907 widget->native_widget_private();
1909 base::string16 empty;
1910 base::string16 s1(base::UTF8ToUTF16("Title1"));
1911 base::string16 s2(base::UTF8ToUTF16("Title2"));
1912 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1914 // The widget starts with no title, setting empty should not change
1915 // anything.
1916 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1917 // Setting the title to something non-empty should cause a change.
1918 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1919 // Setting the title to something else with the same length should cause a
1920 // change.
1921 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1922 // Setting the title to something else with a different length should cause
1923 // a change.
1924 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1925 // Setting the title to the same thing twice should not cause a change.
1926 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1928 widget->CloseNow();
1932 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1933 // Use the default NativeWidget.
1934 bool desktop_native_widget = false;
1935 RunTest(desktop_native_widget);
1938 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1939 #if !defined(OS_CHROMEOS)
1940 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1941 // Override to use a DesktopNativeWidget.
1942 bool desktop_native_widget = true;
1943 RunTest(desktop_native_widget);
1945 #endif // !OS_CHROMEOS
1947 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1948 Widget* widget = new Widget;
1949 Widget::InitParams params =
1950 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1951 widget->Init(params);
1953 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1955 widget->SetSize(gfx::Size(100, 100));
1956 widget->Show();
1958 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1960 WidgetDeletionObserver deletion_observer(widget);
1961 generator.ClickLeftButton();
1962 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1964 // Yay we did not crash!
1967 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
1968 #if !defined(OS_MACOSX) || defined(USE_AURA)
1970 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1971 Widget* widget = new Widget;
1972 Widget::InitParams params =
1973 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1974 widget->Init(params);
1976 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1978 widget->SetSize(gfx::Size(100, 100));
1979 widget->Show();
1981 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1983 WidgetDeletionObserver deletion_observer(widget);
1984 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1985 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1987 // Yay we did not crash!
1990 #endif // !defined(OS_MACOSX) || defined(USE_AURA)
1992 // See description of RunGetNativeThemeFromDestructor() for details.
1993 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1994 public:
1995 GetNativeThemeFromDestructorView() {}
1996 ~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
1998 View* GetContentsView() override { return this; }
2000 private:
2001 void VerifyNativeTheme() {
2002 ASSERT_TRUE(GetNativeTheme() != NULL);
2005 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
2008 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
2009 // crash. |is_first_run| is true if this is the first call. A return value of
2010 // true indicates this should be run again with a value of false.
2011 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
2012 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
2013 bool is_first_run) {
2014 bool needs_second_run = false;
2015 // Destroyed by CloseNow() below.
2016 Widget* widget = new Widget;
2017 Widget::InitParams params(in_params);
2018 // Deletes itself when the Widget is destroyed.
2019 params.delegate = new GetNativeThemeFromDestructorView;
2020 #if !defined(OS_CHROMEOS)
2021 if (is_first_run) {
2022 params.native_widget = new PlatformDesktopNativeWidget(widget);
2023 needs_second_run = true;
2025 #endif
2026 widget->Init(params);
2027 widget->CloseNow();
2028 return needs_second_run;
2031 // See description of RunGetNativeThemeFromDestructor() for details.
2032 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
2033 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2034 if (RunGetNativeThemeFromDestructor(params, true))
2035 RunGetNativeThemeFromDestructor(params, false);
2038 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
2039 // destroyed.
2040 class CloseDestroysWidget : public Widget {
2041 public:
2042 explicit CloseDestroysWidget(bool* destroyed)
2043 : destroyed_(destroyed) {
2046 ~CloseDestroysWidget() override {
2047 if (destroyed_) {
2048 *destroyed_ = true;
2049 base::MessageLoop::current()->QuitNow();
2053 void Detach() { destroyed_ = NULL; }
2055 private:
2056 // If non-null set to true from destructor.
2057 bool* destroyed_;
2059 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
2062 // An observer that registers that an animation has ended.
2063 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
2064 public:
2065 AnimationEndObserver() : animation_completed_(false) {}
2066 ~AnimationEndObserver() override {}
2068 bool animation_completed() const { return animation_completed_; }
2070 // ui::ImplicitAnimationObserver:
2071 void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
2073 private:
2074 bool animation_completed_;
2076 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
2079 // An observer that registers the bounds of a widget on destruction.
2080 class WidgetBoundsObserver : public WidgetObserver {
2081 public:
2082 WidgetBoundsObserver() {}
2083 ~WidgetBoundsObserver() override {}
2085 gfx::Rect bounds() { return bounds_; }
2087 // WidgetObserver:
2088 void OnWidgetDestroying(Widget* widget) override {
2089 bounds_ = widget->GetWindowBoundsInScreen();
2092 private:
2093 gfx::Rect bounds_;
2095 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
2098 // Verifies Close() results in destroying.
2099 TEST_F(WidgetTest, CloseDestroys) {
2100 bool destroyed = false;
2101 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
2102 Widget::InitParams params =
2103 CreateParams(views::Widget::InitParams::TYPE_MENU);
2104 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
2105 #if !defined(OS_CHROMEOS)
2106 params.native_widget = new PlatformDesktopNativeWidget(widget);
2107 #endif
2108 widget->Init(params);
2109 widget->Show();
2110 widget->Hide();
2111 widget->Close();
2112 EXPECT_FALSE(destroyed);
2113 // Run the message loop as Close() asynchronously deletes.
2114 base::RunLoop().Run();
2115 EXPECT_TRUE(destroyed);
2116 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
2117 if (!destroyed) {
2118 widget->Detach();
2119 widget->CloseNow();
2123 // Tests that killing a widget while animating it does not crash.
2124 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
2125 scoped_ptr<Widget> widget(new Widget);
2126 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2127 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2128 params.bounds = gfx::Rect(50, 50, 250, 250);
2129 widget->Init(params);
2130 AnimationEndObserver animation_observer;
2131 WidgetBoundsObserver widget_observer;
2132 gfx::Rect bounds(0, 0, 50, 50);
2134 // Normal animations for tests have ZERO_DURATION, make sure we are actually
2135 // animating the movement.
2136 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
2137 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2138 ui::ScopedLayerAnimationSettings animation_settings(
2139 widget->GetLayer()->GetAnimator());
2140 animation_settings.AddObserver(&animation_observer);
2141 widget->AddObserver(&widget_observer);
2142 widget->Show();
2144 // Animate the bounds change.
2145 widget->SetBounds(bounds);
2146 widget.reset();
2147 EXPECT_FALSE(animation_observer.animation_completed());
2149 EXPECT_TRUE(animation_observer.animation_completed());
2150 EXPECT_EQ(widget_observer.bounds(), bounds);
2153 // Tests that we do not crash when a Widget is destroyed by going out of
2154 // scope (as opposed to being explicitly deleted by its NativeWidget).
2155 TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
2156 scoped_ptr<Widget> widget(new Widget);
2157 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2158 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2159 widget->Init(params);
2162 // Tests that we do not crash when a Widget is destroyed before it finishes
2163 // processing of pending input events in the message loop.
2164 TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
2165 scoped_ptr<Widget> widget(new Widget);
2166 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
2167 params.bounds = gfx::Rect(0, 0, 200, 200);
2168 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2169 widget->Init(params);
2170 widget->Show();
2172 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
2173 generator.MoveMouseTo(10, 10);
2175 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2176 #if defined(OS_MACOSX) && !defined(USE_AURA)
2177 generator.ClickLeftButton();
2178 #else
2179 generator.PressTouch();
2180 #endif
2181 widget.reset();
2184 // A view that consumes mouse-pressed event and gesture-tap-down events.
2185 class RootViewTestView : public View {
2186 public:
2187 RootViewTestView(): View() {}
2189 private:
2190 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
2192 void OnGestureEvent(ui::GestureEvent* event) override {
2193 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
2194 event->SetHandled();
2198 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
2199 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
2200 #if defined(OS_WIN)
2201 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2202 DISABLED_TestRootViewHandlersWhenHidden
2203 #else
2204 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
2205 TestRootViewHandlersWhenHidden
2206 #endif
2207 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
2208 Widget* widget = CreateTopLevelNativeWidget();
2209 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2210 View* view = new RootViewTestView();
2211 view->SetBounds(0, 0, 300, 300);
2212 internal::RootView* root_view =
2213 static_cast<internal::RootView*>(widget->GetRootView());
2214 root_view->AddChildView(view);
2216 // Check RootView::mouse_pressed_handler_.
2217 widget->Show();
2218 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2219 gfx::Point click_location(45, 15);
2220 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
2221 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2222 ui::EF_LEFT_MOUSE_BUTTON);
2223 widget->OnMouseEvent(&press);
2224 EXPECT_EQ(view, GetMousePressedHandler(root_view));
2225 widget->Hide();
2226 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
2228 // Check RootView::mouse_move_handler_.
2229 widget->Show();
2230 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2231 gfx::Point move_location(45, 15);
2232 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
2233 ui::EventTimeForNow(), 0, 0);
2234 widget->OnMouseEvent(&move);
2235 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
2236 widget->Hide();
2237 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
2239 // Check RootView::gesture_handler_.
2240 widget->Show();
2241 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2242 ui::GestureEvent tap_down(15,
2245 base::TimeDelta(),
2246 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2247 widget->OnGestureEvent(&tap_down);
2248 EXPECT_EQ(view, GetGestureHandler(root_view));
2249 widget->Hide();
2250 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2252 widget->Close();
2255 // Convenience to make constructing a GestureEvent simpler.
2256 class GestureEventForTest : public ui::GestureEvent {
2257 public:
2258 GestureEventForTest(ui::EventType type, int x, int y)
2259 : GestureEvent(x,
2262 base::TimeDelta(),
2263 ui::GestureEventDetails(type)) {}
2265 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
2266 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2269 // Tests that the |gesture_handler_| member in RootView is always NULL
2270 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2271 // the release of the final touch point on the screen, but that
2272 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2273 // point do not modify |gesture_handler_|.
2274 TEST_F(WidgetTest, GestureEndEvents) {
2275 Widget* widget = CreateTopLevelNativeWidget();
2276 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2277 EventCountView* view = new EventCountView();
2278 view->SetBounds(0, 0, 300, 300);
2279 internal::RootView* root_view =
2280 static_cast<internal::RootView*>(widget->GetRootView());
2281 root_view->AddChildView(view);
2282 widget->Show();
2284 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2285 // the gesture handler.
2286 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2287 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2288 widget->OnGestureEvent(&end);
2289 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2291 // Change the handle mode of |view| to indicate that it would like
2292 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2293 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2294 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2295 widget->OnGestureEvent(&tap);
2296 EXPECT_TRUE(tap.handled());
2297 EXPECT_EQ(view, GetGestureHandler(root_view));
2299 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2300 // corresponding to a second touch point, but should be reset to NULL by a
2301 // ui::ET_GESTURE_END corresponding to the final touch point.
2302 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2303 details.set_touch_points(2);
2304 GestureEventForTest end_second_touch_point(details, 15, 15);
2305 widget->OnGestureEvent(&end_second_touch_point);
2306 EXPECT_EQ(view, GetGestureHandler(root_view));
2308 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2309 widget->OnGestureEvent(&end);
2310 EXPECT_TRUE(end.handled());
2311 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2313 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2314 // mode of |view| to indicate that it does not want to handle any
2315 // further events.
2316 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2317 widget->OnGestureEvent(&tap);
2318 EXPECT_TRUE(tap.handled());
2319 EXPECT_EQ(view, GetGestureHandler(root_view));
2320 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2322 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2323 // corresponding to a second touch point, but should be reset to NULL by a
2324 // ui::ET_GESTURE_END corresponding to the final touch point.
2325 end_second_touch_point = GestureEventForTest(details, 15, 15);
2326 widget->OnGestureEvent(&end_second_touch_point);
2327 EXPECT_EQ(view, GetGestureHandler(root_view));
2329 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2330 widget->OnGestureEvent(&end);
2331 EXPECT_FALSE(end.handled());
2332 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2334 widget->Close();
2337 // Tests that gesture events which should not be processed (because
2338 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2339 // dispatched to any views.
2340 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2341 Widget* widget = CreateTopLevelNativeWidget();
2342 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2344 // Define a hierarchy of four views (coordinates are in
2345 // their parent coordinate space).
2346 // v1 (0, 0, 300, 300)
2347 // v2 (0, 0, 100, 100)
2348 // v3 (0, 0, 50, 50)
2349 // v4(0, 0, 10, 10)
2350 EventCountView* v1 = new EventCountView();
2351 v1->SetBounds(0, 0, 300, 300);
2352 EventCountView* v2 = new EventCountView();
2353 v2->SetBounds(0, 0, 100, 100);
2354 EventCountView* v3 = new EventCountView();
2355 v3->SetBounds(0, 0, 50, 50);
2356 EventCountView* v4 = new EventCountView();
2357 v4->SetBounds(0, 0, 10, 10);
2358 internal::RootView* root_view =
2359 static_cast<internal::RootView*>(widget->GetRootView());
2360 root_view->AddChildView(v1);
2361 v1->AddChildView(v2);
2362 v2->AddChildView(v3);
2363 v3->AddChildView(v4);
2365 widget->Show();
2367 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2368 // they should be marked as handled by OnEventProcessingStarted().
2369 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2370 widget->OnGestureEvent(&begin);
2371 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2372 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2373 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2374 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2375 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2376 EXPECT_TRUE(begin.handled());
2377 v1->ResetCounts();
2378 v2->ResetCounts();
2379 v3->ResetCounts();
2380 v4->ResetCounts();
2382 // ui::ET_GESTURE_END events should not be seen by any view when there is
2383 // no default gesture handler set, but they should be marked as handled by
2384 // OnEventProcessingStarted().
2385 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2386 widget->OnGestureEvent(&end);
2387 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2388 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2389 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2390 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2391 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2392 EXPECT_TRUE(end.handled());
2393 v1->ResetCounts();
2394 v2->ResetCounts();
2395 v3->ResetCounts();
2396 v4->ResetCounts();
2398 // ui::ET_GESTURE_END events not corresponding to the release of the
2399 // final touch point should never be seen by any view, but they should
2400 // be marked as handled by OnEventProcessingStarted().
2401 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2402 details.set_touch_points(2);
2403 GestureEventForTest end_second_touch_point(details, 5, 5);
2404 widget->OnGestureEvent(&end_second_touch_point);
2405 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2406 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2407 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2408 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2409 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2410 EXPECT_TRUE(end_second_touch_point.handled());
2411 v1->ResetCounts();
2412 v2->ResetCounts();
2413 v3->ResetCounts();
2414 v4->ResetCounts();
2416 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2417 // there is no default gesture handler set, but they should be marked as
2418 // handled by OnEventProcessingStarted().
2419 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2420 widget->OnGestureEvent(&scroll_update);
2421 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2422 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2423 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2424 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2425 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2426 EXPECT_TRUE(scroll_update.handled());
2427 v1->ResetCounts();
2428 v2->ResetCounts();
2429 v3->ResetCounts();
2430 v4->ResetCounts();
2432 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2433 // there is no default gesture handler set, but they should be marked as
2434 // handled by OnEventProcessingStarted().
2435 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2436 widget->OnGestureEvent(&scroll_end);
2437 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2438 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2439 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2440 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2441 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2442 EXPECT_TRUE(scroll_end.handled());
2443 v1->ResetCounts();
2444 v2->ResetCounts();
2445 v3->ResetCounts();
2446 v4->ResetCounts();
2448 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2449 // there is no default gesture handler set, but they should be marked as
2450 // handled by OnEventProcessingStarted().
2451 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2452 widget->OnGestureEvent(&scroll_fling_start);
2453 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2454 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2455 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2456 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2457 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2458 EXPECT_TRUE(scroll_fling_start.handled());
2459 v1->ResetCounts();
2460 v2->ResetCounts();
2461 v3->ResetCounts();
2462 v4->ResetCounts();
2464 widget->Close();
2467 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2468 // in a view hierarchy and that the default gesture handler in RootView is set
2469 // correctly.
2470 TEST_F(WidgetTest, GestureEventDispatch) {
2471 Widget* widget = CreateTopLevelNativeWidget();
2472 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2474 // Define a hierarchy of four views (coordinates are in
2475 // their parent coordinate space).
2476 // v1 (0, 0, 300, 300)
2477 // v2 (0, 0, 100, 100)
2478 // v3 (0, 0, 50, 50)
2479 // v4(0, 0, 10, 10)
2480 EventCountView* v1 = new EventCountView();
2481 v1->SetBounds(0, 0, 300, 300);
2482 EventCountView* v2 = new EventCountView();
2483 v2->SetBounds(0, 0, 100, 100);
2484 EventCountView* v3 = new EventCountView();
2485 v3->SetBounds(0, 0, 50, 50);
2486 EventCountView* v4 = new EventCountView();
2487 v4->SetBounds(0, 0, 10, 10);
2488 internal::RootView* root_view =
2489 static_cast<internal::RootView*>(widget->GetRootView());
2490 root_view->AddChildView(v1);
2491 v1->AddChildView(v2);
2492 v2->AddChildView(v3);
2493 v3->AddChildView(v4);
2495 widget->Show();
2497 // No gesture handler is set in the root view and none of the views in the
2498 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2499 // event should be dispatched to all views in the hierarchy, the gesture
2500 // handler should remain unset, and the event should remain unhandled.
2501 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2502 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2503 widget->OnGestureEvent(&tap);
2504 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2505 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2506 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2507 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2508 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2509 EXPECT_FALSE(tap.handled());
2511 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2512 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2513 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2514 // and the event should be marked as handled.
2515 v1->ResetCounts();
2516 v2->ResetCounts();
2517 v3->ResetCounts();
2518 v4->ResetCounts();
2519 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2520 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2521 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2522 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2523 widget->OnGestureEvent(&tap);
2524 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2525 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2526 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2527 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2528 EXPECT_EQ(v3, GetGestureHandler(root_view));
2529 EXPECT_TRUE(tap.handled());
2531 // The gesture handler is set to |v3| and all views handle all gesture event
2532 // types. In this case subsequent gesture events should only be dispatched to
2533 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2534 v1->ResetCounts();
2535 v2->ResetCounts();
2536 v3->ResetCounts();
2537 v4->ResetCounts();
2538 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2539 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2540 widget->OnGestureEvent(&tap);
2541 EXPECT_TRUE(tap.handled());
2542 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2543 widget->OnGestureEvent(&show_press);
2544 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2545 widget->OnGestureEvent(&tap);
2546 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2547 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2548 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2549 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2550 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2551 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2552 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2553 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2554 EXPECT_TRUE(tap.handled());
2555 EXPECT_TRUE(show_press.handled());
2556 EXPECT_EQ(v3, GetGestureHandler(root_view));
2558 // The gesture handler is set to |v3|, but |v3| does not handle
2559 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2560 // only to |v3|, but the event should remain unhandled. The gesture handler
2561 // should remain as |v3|.
2562 v1->ResetCounts();
2563 v2->ResetCounts();
2564 v3->ResetCounts();
2565 v4->ResetCounts();
2566 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2567 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2568 widget->OnGestureEvent(&tap);
2569 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2570 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2571 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2572 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2573 EXPECT_FALSE(tap.handled());
2574 EXPECT_EQ(v3, GetGestureHandler(root_view));
2576 widget->Close();
2579 // Tests that gesture scroll events will change the default gesture handler in
2580 // RootView if the current handler to which they are dispatched does not handle
2581 // gesture scroll events.
2582 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2583 Widget* widget = CreateTopLevelNativeWidget();
2584 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2586 // Define a hierarchy of four views (coordinates are in
2587 // their parent coordinate space).
2588 // v1 (0, 0, 300, 300)
2589 // v2 (0, 0, 100, 100)
2590 // v3 (0, 0, 50, 50)
2591 // v4(0, 0, 10, 10)
2592 EventCountView* v1 = new EventCountView();
2593 v1->SetBounds(0, 0, 300, 300);
2594 EventCountView* v2 = new EventCountView();
2595 v2->SetBounds(0, 0, 100, 100);
2596 EventCountView* v3 = new EventCountView();
2597 v3->SetBounds(0, 0, 50, 50);
2598 EventCountView* v4 = new EventCountView();
2599 v4->SetBounds(0, 0, 10, 10);
2600 internal::RootView* root_view =
2601 static_cast<internal::RootView*>(widget->GetRootView());
2602 root_view->AddChildView(v1);
2603 v1->AddChildView(v2);
2604 v2->AddChildView(v3);
2605 v3->AddChildView(v4);
2607 widget->Show();
2609 // Change the handle mode of |v3| to indicate that it would like to handle
2610 // gesture events.
2611 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2613 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2614 // should bubble up the views hierarchy until it reaches the first view
2615 // that will handle it (|v3|) and then sets the handler to |v3|.
2616 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2617 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2618 widget->OnGestureEvent(&tap_down);
2619 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2620 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2621 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2622 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2623 EXPECT_EQ(v3, GetGestureHandler(root_view));
2624 EXPECT_TRUE(tap_down.handled());
2625 v1->ResetCounts();
2626 v2->ResetCounts();
2627 v3->ResetCounts();
2628 v4->ResetCounts();
2630 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2631 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2632 widget->OnGestureEvent(&tap_cancel);
2633 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2634 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2635 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2636 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2637 EXPECT_EQ(v3, GetGestureHandler(root_view));
2638 EXPECT_TRUE(tap_cancel.handled());
2639 v1->ResetCounts();
2640 v2->ResetCounts();
2641 v3->ResetCounts();
2642 v4->ResetCounts();
2644 // Change the handle mode of |v3| to indicate that it would no longer like
2645 // to handle events, and change the mode of |v1| to indicate that it would
2646 // like to handle events.
2647 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2648 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2650 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2651 // handler (|v3|) does not handle scroll events, the event should bubble up
2652 // the views hierarchy until it reaches the first view that will handle
2653 // it (|v1|) and then sets the handler to |v1|.
2654 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2655 widget->OnGestureEvent(&scroll_begin);
2656 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2657 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2658 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2659 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2660 EXPECT_EQ(v1, GetGestureHandler(root_view));
2661 EXPECT_TRUE(scroll_begin.handled());
2662 v1->ResetCounts();
2663 v2->ResetCounts();
2664 v3->ResetCounts();
2665 v4->ResetCounts();
2667 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2668 // directly.
2669 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2670 widget->OnGestureEvent(&scroll_update);
2671 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2672 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2673 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2674 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2675 EXPECT_EQ(v1, GetGestureHandler(root_view));
2676 EXPECT_TRUE(scroll_update.handled());
2677 v1->ResetCounts();
2678 v2->ResetCounts();
2679 v3->ResetCounts();
2680 v4->ResetCounts();
2682 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2683 // directly and should not reset the gesture handler.
2684 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2685 widget->OnGestureEvent(&scroll_end);
2686 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2687 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2688 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2689 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2690 EXPECT_EQ(v1, GetGestureHandler(root_view));
2691 EXPECT_TRUE(scroll_end.handled());
2692 v1->ResetCounts();
2693 v2->ResetCounts();
2694 v3->ResetCounts();
2695 v4->ResetCounts();
2697 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2698 // still be dispatched to |v1| directly.
2699 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2700 widget->OnGestureEvent(&pinch_begin);
2701 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2702 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2703 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2704 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2705 EXPECT_EQ(v1, GetGestureHandler(root_view));
2706 EXPECT_TRUE(pinch_begin.handled());
2707 v1->ResetCounts();
2708 v2->ResetCounts();
2709 v3->ResetCounts();
2710 v4->ResetCounts();
2712 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2713 // set the gesture handler to NULL.
2714 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2715 widget->OnGestureEvent(&end);
2716 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2717 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2718 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2719 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2720 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2721 EXPECT_TRUE(end.handled());
2723 widget->Close();
2726 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2727 // that when a gesture event bubbles up a View hierarchy, the location
2728 // of a gesture event seen by each View is in the local coordinate space
2729 // of that View.
2730 class GestureLocationView : public EventCountView {
2731 public:
2732 GestureLocationView() {}
2733 ~GestureLocationView() override {}
2735 void set_expected_location(gfx::Point expected_location) {
2736 expected_location_ = expected_location;
2739 // EventCountView:
2740 void OnGestureEvent(ui::GestureEvent* event) override {
2741 EventCountView::OnGestureEvent(event);
2743 // Verify that the location of |event| is in the local coordinate
2744 // space of |this|.
2745 EXPECT_EQ(expected_location_, event->location());
2748 private:
2749 // The expected location of a gesture event dispatched to |this|.
2750 gfx::Point expected_location_;
2752 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2755 // Verifies that the location of a gesture event is always in the local
2756 // coordinate space of the View receiving the event while bubbling.
2757 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2758 Widget* widget = CreateTopLevelNativeWidget();
2759 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2761 // Define a hierarchy of three views (coordinates shown below are in the
2762 // coordinate space of the root view, but the coordinates used for
2763 // SetBounds() are in their parent coordinate space).
2764 // v1 (50, 50, 150, 150)
2765 // v2 (100, 70, 50, 80)
2766 // v3 (120, 100, 10, 10)
2767 GestureLocationView* v1 = new GestureLocationView();
2768 v1->SetBounds(50, 50, 150, 150);
2769 GestureLocationView* v2 = new GestureLocationView();
2770 v2->SetBounds(50, 20, 50, 80);
2771 GestureLocationView* v3 = new GestureLocationView();
2772 v3->SetBounds(20, 30, 10, 10);
2773 internal::RootView* root_view =
2774 static_cast<internal::RootView*>(widget->GetRootView());
2775 root_view->AddChildView(v1);
2776 v1->AddChildView(v2);
2777 v2->AddChildView(v3);
2779 widget->Show();
2781 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2782 // This event is contained within all of |v1|, |v2|, and |v3|.
2783 gfx::Point location_in_root(125, 105);
2784 GestureEventForTest tap(
2785 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2787 // Calculate the location of the event in the local coordinate spaces
2788 // of each of the views.
2789 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2790 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2791 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2792 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2793 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2794 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2796 // Dispatch the event. When each view receives the event, its location should
2797 // be in the local coordinate space of that view (see the check made by
2798 // GestureLocationView). After dispatch is complete the event's location
2799 // should be in the root coordinate space.
2800 v1->set_expected_location(location_in_v1);
2801 v2->set_expected_location(location_in_v2);
2802 v3->set_expected_location(location_in_v3);
2803 widget->OnGestureEvent(&tap);
2804 EXPECT_EQ(location_in_root, tap.location());
2806 // Verify that each view did in fact see the event.
2807 EventCountView* view1 = v1;
2808 EventCountView* view2 = v2;
2809 EventCountView* view3 = v3;
2810 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2811 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2812 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2814 widget->Close();
2817 // Verifies that disabled views are permitted to be set as the default gesture
2818 // handler in RootView. Also verifies that gesture events targeted to a disabled
2819 // view are not actually dispatched to the view, but are still marked as
2820 // handled.
2821 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2822 Widget* widget = CreateTopLevelNativeWidget();
2823 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2825 // Define a hierarchy of four views (coordinates are in
2826 // their parent coordinate space).
2827 // v1 (0, 0, 300, 300)
2828 // v2 (0, 0, 100, 100)
2829 // v3 (0, 0, 50, 50)
2830 // v4(0, 0, 10, 10)
2831 EventCountView* v1 = new EventCountView();
2832 v1->SetBounds(0, 0, 300, 300);
2833 EventCountView* v2 = new EventCountView();
2834 v2->SetBounds(0, 0, 100, 100);
2835 EventCountView* v3 = new EventCountView();
2836 v3->SetBounds(0, 0, 50, 50);
2837 EventCountView* v4 = new EventCountView();
2838 v4->SetBounds(0, 0, 10, 10);
2839 internal::RootView* root_view =
2840 static_cast<internal::RootView*>(widget->GetRootView());
2841 root_view->AddChildView(v1);
2842 v1->AddChildView(v2);
2843 v2->AddChildView(v3);
2844 v3->AddChildView(v4);
2846 widget->Show();
2848 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2849 // disabled.
2850 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2851 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2852 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2853 v3->SetEnabled(false);
2855 // No gesture handler is set in the root view. In this case the tap event
2856 // should be dispatched only to |v4|, the gesture handler should be set to
2857 // |v3|, and the event should be marked as handled.
2858 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2859 widget->OnGestureEvent(&tap);
2860 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2861 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2862 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2863 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2864 EXPECT_EQ(v3, GetGestureHandler(root_view));
2865 EXPECT_TRUE(tap.handled());
2866 v1->ResetCounts();
2867 v2->ResetCounts();
2868 v3->ResetCounts();
2869 v4->ResetCounts();
2871 // A subsequent gesture event should be marked as handled but not dispatched.
2872 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2873 widget->OnGestureEvent(&tap);
2874 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2875 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2876 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2877 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2878 EXPECT_EQ(v3, GetGestureHandler(root_view));
2879 EXPECT_TRUE(tap.handled());
2880 v1->ResetCounts();
2881 v2->ResetCounts();
2882 v3->ResetCounts();
2883 v4->ResetCounts();
2885 // A GESTURE_END should reset the default gesture handler to NULL. It should
2886 // also not be dispatched to |v3| but still marked as handled.
2887 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2888 widget->OnGestureEvent(&end);
2889 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2890 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2891 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2892 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2893 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2894 EXPECT_TRUE(end.handled());
2895 v1->ResetCounts();
2896 v2->ResetCounts();
2897 v3->ResetCounts();
2898 v4->ResetCounts();
2900 // Change the handle mode of |v3| to indicate that it would no longer like
2901 // to handle events which are dispatched to it.
2902 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2904 // No gesture handler is set in the root view. In this case the tap event
2905 // should be dispatched only to |v4| and the event should be marked as
2906 // handled. Furthermore, the gesture handler should be set to
2907 // |v3|; even though |v3| does not explicitly handle events, it is a
2908 // valid target for the tap event because it is disabled.
2909 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2910 widget->OnGestureEvent(&tap);
2911 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2912 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2913 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2914 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2915 EXPECT_EQ(v3, GetGestureHandler(root_view));
2916 EXPECT_TRUE(tap.handled());
2917 v1->ResetCounts();
2918 v2->ResetCounts();
2919 v3->ResetCounts();
2920 v4->ResetCounts();
2922 // A GESTURE_END should reset the default gesture handler to NULL. It should
2923 // also not be dispatched to |v3| but still marked as handled.
2924 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2925 widget->OnGestureEvent(&end);
2926 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2927 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2928 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2929 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2930 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2931 EXPECT_TRUE(end.handled());
2933 widget->Close();
2936 // Test the result of Widget::GetAllChildWidgets().
2937 TEST_F(WidgetTest, GetAllChildWidgets) {
2938 // Create the following widget hierarchy:
2940 // toplevel
2941 // +-- w1
2942 // +-- w11
2943 // +-- w2
2944 // +-- w21
2945 // +-- w22
2946 Widget* toplevel = CreateTopLevelPlatformWidget();
2947 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2948 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2949 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2950 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2951 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2953 std::set<Widget*> expected;
2954 expected.insert(toplevel);
2955 expected.insert(w1);
2956 expected.insert(w11);
2957 expected.insert(w2);
2958 expected.insert(w21);
2959 expected.insert(w22);
2961 std::set<Widget*> widgets;
2962 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2964 EXPECT_EQ(expected.size(), widgets.size());
2965 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2968 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2969 // a vector.
2970 class DestroyedTrackingView : public View {
2971 public:
2972 DestroyedTrackingView(const std::string& name,
2973 std::vector<std::string>* add_to)
2974 : name_(name),
2975 add_to_(add_to) {
2978 ~DestroyedTrackingView() override { add_to_->push_back(name_); }
2980 private:
2981 const std::string name_;
2982 std::vector<std::string>* add_to_;
2984 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2987 class WidgetChildDestructionTest : public WidgetTest {
2988 public:
2989 WidgetChildDestructionTest() {}
2991 // Creates a top level and a child, destroys the child and verifies the views
2992 // of the child are destroyed before the views of the parent.
2993 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2994 bool child_has_desktop_native_widget_aura) {
2995 // When a View is destroyed its name is added here.
2996 std::vector<std::string> destroyed;
2998 Widget* top_level = new Widget;
2999 Widget::InitParams params =
3000 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
3001 #if !defined(OS_CHROMEOS)
3002 if (top_level_has_desktop_native_widget_aura)
3003 params.native_widget = new PlatformDesktopNativeWidget(top_level);
3004 #endif
3005 top_level->Init(params);
3006 top_level->GetRootView()->AddChildView(
3007 new DestroyedTrackingView("parent", &destroyed));
3008 top_level->Show();
3010 Widget* child = new Widget;
3011 Widget::InitParams child_params =
3012 CreateParams(views::Widget::InitParams::TYPE_POPUP);
3013 child_params.parent = top_level->GetNativeView();
3014 #if !defined(OS_CHROMEOS)
3015 if (child_has_desktop_native_widget_aura)
3016 child_params.native_widget = new PlatformDesktopNativeWidget(child);
3017 #endif
3018 child->Init(child_params);
3019 child->GetRootView()->AddChildView(
3020 new DestroyedTrackingView("child", &destroyed));
3021 child->Show();
3023 // Should trigger destruction of the child too.
3024 top_level->native_widget_private()->CloseNow();
3026 // Child should be destroyed first.
3027 ASSERT_EQ(2u, destroyed.size());
3028 EXPECT_EQ("child", destroyed[0]);
3029 EXPECT_EQ("parent", destroyed[1]);
3032 private:
3033 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
3036 #if !defined(OS_CHROMEOS)
3037 // See description of RunDestroyChildWidgetsTest(). Parent uses
3038 // DesktopNativeWidgetAura.
3039 TEST_F(WidgetChildDestructionTest,
3040 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
3041 RunDestroyChildWidgetsTest(true, false);
3044 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
3045 // DesktopNativeWidgetAura.
3046 TEST_F(WidgetChildDestructionTest,
3047 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
3048 RunDestroyChildWidgetsTest(true, true);
3050 #endif // !defined(OS_CHROMEOS)
3052 // See description of RunDestroyChildWidgetsTest().
3053 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
3054 RunDestroyChildWidgetsTest(false, false);
3057 #if !defined(OS_CHROMEOS)
3058 // Provides functionality to create a window modal dialog.
3059 class ModalDialogDelegate : public DialogDelegateView {
3060 public:
3061 ModalDialogDelegate() {}
3062 ~ModalDialogDelegate() override {}
3064 // WidgetDelegate overrides.
3065 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
3067 private:
3068 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
3071 // This test verifies that whether mouse events when a modal dialog is
3072 // displayed are eaten or recieved by the dialog.
3073 TEST_F(WidgetTest, WindowMouseModalityTest) {
3074 // Create a top level widget.
3075 Widget top_level_widget;
3076 Widget::InitParams init_params =
3077 CreateParams(Widget::InitParams::TYPE_WINDOW);
3078 init_params.show_state = ui::SHOW_STATE_NORMAL;
3079 gfx::Rect initial_bounds(0, 0, 500, 500);
3080 init_params.bounds = initial_bounds;
3081 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3082 init_params.native_widget =
3083 new PlatformDesktopNativeWidget(&top_level_widget);
3084 top_level_widget.Init(init_params);
3085 top_level_widget.Show();
3086 EXPECT_TRUE(top_level_widget.IsVisible());
3088 // Create a view and validate that a mouse moves makes it to the view.
3089 EventCountView* widget_view = new EventCountView();
3090 widget_view->SetBounds(0, 0, 10, 10);
3091 top_level_widget.GetRootView()->AddChildView(widget_view);
3093 gfx::Point cursor_location_main(5, 5);
3094 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main,
3095 cursor_location_main, ui::EventTimeForNow(),
3096 ui::EF_NONE, ui::EF_NONE);
3097 ui::EventDispatchDetails details =
3098 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
3099 ASSERT_FALSE(details.dispatcher_destroyed);
3101 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
3102 widget_view->ResetCounts();
3104 // Create a modal dialog and validate that a mouse down message makes it to
3105 // the main view within the dialog.
3107 // This instance will be destroyed when the dialog is destroyed.
3108 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3110 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3111 dialog_delegate, NULL, top_level_widget.GetNativeView());
3112 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3113 EventCountView* dialog_widget_view = new EventCountView();
3114 dialog_widget_view->SetBounds(0, 0, 50, 50);
3115 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
3116 modal_dialog_widget->Show();
3117 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3119 gfx::Point cursor_location_dialog(100, 100);
3120 ui::MouseEvent mouse_down_dialog(
3121 ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog,
3122 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
3123 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
3124 &mouse_down_dialog);
3125 ASSERT_FALSE(details.dispatcher_destroyed);
3126 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
3128 // Send a mouse move message to the main window. It should not be received by
3129 // the main window as the modal dialog is still active.
3130 gfx::Point cursor_location_main2(6, 6);
3131 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2,
3132 cursor_location_main2, ui::EventTimeForNow(),
3133 ui::EF_NONE, ui::EF_NONE);
3134 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
3135 &mouse_down_main);
3136 ASSERT_FALSE(details.dispatcher_destroyed);
3137 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
3139 modal_dialog_widget->CloseNow();
3140 top_level_widget.CloseNow();
3143 // Verifies nativeview visbility matches that of Widget visibility when
3144 // SetFullscreen is invoked.
3145 TEST_F(WidgetTest, FullscreenStatePropagated) {
3146 Widget::InitParams init_params =
3147 CreateParams(Widget::InitParams::TYPE_WINDOW);
3148 init_params.show_state = ui::SHOW_STATE_NORMAL;
3149 init_params.bounds = gfx::Rect(0, 0, 500, 500);
3150 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3153 Widget top_level_widget;
3154 top_level_widget.Init(init_params);
3155 top_level_widget.SetFullscreen(true);
3156 EXPECT_EQ(top_level_widget.IsVisible(),
3157 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3158 top_level_widget.CloseNow();
3160 #if !defined(OS_CHROMEOS)
3162 Widget top_level_widget;
3163 init_params.native_widget =
3164 new PlatformDesktopNativeWidget(&top_level_widget);
3165 top_level_widget.Init(init_params);
3166 top_level_widget.SetFullscreen(true);
3167 EXPECT_EQ(top_level_widget.IsVisible(),
3168 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
3169 top_level_widget.CloseNow();
3171 #endif
3173 #if defined(OS_WIN)
3175 // Tests whether we can activate the top level widget when a modal dialog is
3176 // active.
3177 TEST_F(WidgetTest, WindowModalityActivationTest) {
3178 TestDesktopWidgetDelegate widget_delegate;
3179 widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
3181 Widget* top_level_widget = widget_delegate.GetWidget();
3182 top_level_widget->Show();
3183 EXPECT_TRUE(top_level_widget->IsVisible());
3185 HWND win32_window = views::HWNDForWidget(top_level_widget);
3186 EXPECT_TRUE(::IsWindow(win32_window));
3188 // This instance will be destroyed when the dialog is destroyed.
3189 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
3191 // We should be able to activate the window even if the WidgetDelegate
3192 // says no, when a modal dialog is active.
3193 widget_delegate.set_can_activate(false);
3195 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
3196 dialog_delegate, NULL, top_level_widget->GetNativeView());
3197 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
3198 modal_dialog_widget->Show();
3199 EXPECT_TRUE(modal_dialog_widget->IsVisible());
3201 LRESULT activate_result = ::SendMessage(
3202 win32_window,
3203 WM_MOUSEACTIVATE,
3204 reinterpret_cast<WPARAM>(win32_window),
3205 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
3206 EXPECT_EQ(activate_result, MA_ACTIVATE);
3208 modal_dialog_widget->CloseNow();
3210 #endif // defined(OS_WIN)
3211 #endif // !defined(OS_CHROMEOS)
3213 namespace {
3215 class FullscreenAwareFrame : public views::NonClientFrameView {
3216 public:
3217 explicit FullscreenAwareFrame(views::Widget* widget)
3218 : widget_(widget), fullscreen_layout_called_(false) {}
3219 ~FullscreenAwareFrame() override {}
3221 // views::NonClientFrameView overrides:
3222 gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
3223 gfx::Rect GetWindowBoundsForClientBounds(
3224 const gfx::Rect& client_bounds) const override {
3225 return gfx::Rect();
3227 int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
3228 void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {}
3229 void ResetWindowControls() override {}
3230 void UpdateWindowIcon() override {}
3231 void UpdateWindowTitle() override {}
3232 void SizeConstraintsChanged() override {}
3234 // views::View overrides:
3235 void Layout() override {
3236 if (widget_->IsFullscreen())
3237 fullscreen_layout_called_ = true;
3240 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3242 private:
3243 views::Widget* widget_;
3244 bool fullscreen_layout_called_;
3246 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3249 } // namespace
3251 // Tests that frame Layout is called when a widget goes fullscreen without
3252 // changing its size or title.
3253 TEST_F(WidgetTest, FullscreenFrameLayout) {
3254 Widget* widget = CreateTopLevelPlatformWidget();
3255 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3256 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3258 widget->Maximize();
3259 RunPendingMessages();
3261 EXPECT_FALSE(frame->fullscreen_layout_called());
3262 widget->SetFullscreen(true);
3263 widget->Show();
3264 RunPendingMessages();
3266 if (IsTestingSnowLeopard()) {
3267 // Fullscreen is currently ignored on Snow Leopard.
3268 EXPECT_FALSE(frame->fullscreen_layout_called());
3269 } else {
3270 EXPECT_TRUE(frame->fullscreen_layout_called());
3273 widget->CloseNow();
3276 #if !defined(OS_CHROMEOS)
3277 namespace {
3279 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3280 // OnWindowDestroying.
3281 class IsActiveFromDestroyObserver : public WidgetObserver {
3282 public:
3283 IsActiveFromDestroyObserver() {}
3284 ~IsActiveFromDestroyObserver() override {}
3285 void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
3287 private:
3288 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3291 } // namespace
3293 // Verifies Widget::IsActive() invoked from
3294 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3295 TEST_F(WidgetTest, IsActiveFromDestroy) {
3296 // Create two widgets, one a child of the other.
3297 IsActiveFromDestroyObserver observer;
3298 Widget parent_widget;
3299 Widget::InitParams parent_params =
3300 CreateParams(Widget::InitParams::TYPE_POPUP);
3301 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3302 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3303 parent_widget.Init(parent_params);
3304 parent_widget.Show();
3306 Widget child_widget;
3307 Widget::InitParams child_params =
3308 CreateParams(Widget::InitParams::TYPE_POPUP);
3309 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3310 child_params.context = parent_widget.GetNativeWindow();
3311 child_widget.Init(child_params);
3312 child_widget.AddObserver(&observer);
3313 child_widget.Show();
3315 parent_widget.CloseNow();
3317 #endif // !defined(OS_CHROMEOS)
3319 // Tests that events propagate through from the dispatcher with the correct
3320 // event type, and that the different platforms behave the same.
3321 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3322 EventCountView* view = new EventCountView;
3323 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3324 view->SetBounds(10, 10, 50, 40);
3326 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3327 widget->GetRootView()->AddChildView(view);
3329 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3330 widget->Show();
3332 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3333 generator.set_current_location(gfx::Point(20, 20));
3335 generator.ClickLeftButton();
3336 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3337 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3338 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3340 generator.PressRightButton();
3341 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3342 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3343 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3345 generator.ReleaseRightButton();
3346 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3347 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3348 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3350 // Test mouse move events.
3351 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3352 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3354 // Move the mouse within the view (20, 20) -> (30, 30).
3355 generator.MoveMouseTo(gfx::Point(30, 30));
3356 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3357 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3358 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3360 // Move it again - entered count shouldn't change.
3361 generator.MoveMouseTo(gfx::Point(31, 31));
3362 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3363 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3364 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3366 // Move it off the view.
3367 generator.MoveMouseTo(gfx::Point(5, 5));
3368 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3369 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3370 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3372 // Move it back on.
3373 generator.MoveMouseTo(gfx::Point(20, 20));
3374 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3375 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3376 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3378 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3379 generator.DragMouseTo(gfx::Point(40, 40));
3380 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3381 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3382 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3383 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3385 widget->CloseNow();
3388 // Tests that the root view is correctly set up for Widget types that do not
3389 // require a non-client view, before any other views are added to the widget.
3390 // That is, before Widget::ReorderNativeViews() is called which, if called with
3391 // a root view not set, could cause the root view to get resized to the widget.
3392 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3393 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3394 View* root_view = widget->GetRootView();
3396 // Size the root view to exceed the widget bounds.
3397 const gfx::Rect test_rect(0, 0, 500, 500);
3398 root_view->SetBoundsRect(test_rect);
3400 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3402 EXPECT_EQ(test_rect, root_view->bounds());
3403 widget->ReorderNativeViews();
3404 EXPECT_EQ(test_rect, root_view->bounds());
3406 widget->CloseNow();
3409 #if defined(OS_WIN)
3410 // This test validates that sending WM_CHAR/WM_SYSCHAR/WM_SYSDEADCHAR
3411 // messages via the WindowEventTarget interface implemented by the
3412 // HWNDMessageHandler class does not cause a crash due to an unprocessed
3413 // event
3414 TEST_F(WidgetTest, CharMessagesAsKeyboardMessagesDoesNotCrash) {
3415 Widget widget;
3416 Widget::InitParams params =
3417 CreateParams(Widget::InitParams::TYPE_WINDOW);
3418 params.native_widget = new PlatformDesktopNativeWidget(&widget);
3419 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3420 widget.Init(params);
3421 widget.Show();
3423 ui::WindowEventTarget* target =
3424 reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
3425 widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
3426 ui::WindowEventTarget::kWin32InputEventTarget));
3427 EXPECT_NE(nullptr, target);
3428 bool handled = false;
3429 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled);
3430 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled);
3431 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled);
3432 widget.CloseNow();
3434 #endif
3436 } // namespace test
3437 } // namespace views