Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / views / widget / widget_unittest.cc
blob96bf01207e478d1f366c4a7842e9017dd240a876
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <set>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_processor.h"
20 #include "ui/events/event_utils.h"
21 #include "ui/events/test/event_generator.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/gfx/point.h"
24 #include "ui/views/bubble/bubble_delegate.h"
25 #include "ui/views/controls/textfield/textfield.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/test/widget_test.h"
28 #include "ui/views/views_delegate.h"
29 #include "ui/views/widget/native_widget_delegate.h"
30 #include "ui/views/widget/root_view.h"
31 #include "ui/views/widget/widget_deletion_observer.h"
32 #include "ui/views/window/dialog_delegate.h"
33 #include "ui/views/window/native_frame_view.h"
35 #if defined(OS_WIN)
36 #include "ui/views/win/hwnd_util.h"
37 #endif
39 namespace views {
40 namespace test {
42 // A view that keeps track of the events it receives, optionally consuming them.
43 class EventCountView : public View {
44 public:
45 // Whether to call SetHandled() on events as they are received. For some event
46 // types, this will allow EventCountView to receives future events in the
47 // event sequence, such as a drag.
48 enum HandleMode {
49 PROPAGATE_EVENTS,
50 CONSUME_EVENTS
53 EventCountView()
54 : last_flags_(0),
55 handle_mode_(PROPAGATE_EVENTS) {}
57 virtual ~EventCountView() {}
59 int GetEventCount(ui::EventType type) {
60 return event_count_[type];
63 void ResetCounts() {
64 event_count_.clear();
67 int last_flags() const {
68 return last_flags_;
71 void set_handle_mode(HandleMode handle_mode) {
72 handle_mode_ = handle_mode;
75 protected:
76 // Overridden from View:
77 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
78 // MouseMove events are not re-dispatched from the RootView.
79 ++event_count_[ui::ET_MOUSE_MOVED];
80 last_flags_ = 0;
83 // Overridden from ui::EventHandler:
84 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
85 RecordEvent(event);
87 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
88 RecordEvent(event);
90 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
91 RecordEvent(event);
93 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
94 RecordEvent(event);
97 private:
98 void RecordEvent(ui::Event* event) {
99 ++event_count_[event->type()];
100 last_flags_ = event->flags();
101 if (handle_mode_ == CONSUME_EVENTS)
102 event->SetHandled();
105 std::map<ui::EventType, int> event_count_;
106 int last_flags_;
107 HandleMode handle_mode_;
109 DISALLOW_COPY_AND_ASSIGN(EventCountView);
112 // A view that keeps track of the events it receives, and consumes all scroll
113 // gesture events and ui::ET_SCROLL events.
114 class ScrollableEventCountView : public EventCountView {
115 public:
116 ScrollableEventCountView() {}
117 virtual ~ScrollableEventCountView() {}
119 private:
120 // Overridden from ui::EventHandler:
121 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
122 EventCountView::OnGestureEvent(event);
123 switch (event->type()) {
124 case ui::ET_GESTURE_SCROLL_BEGIN:
125 case ui::ET_GESTURE_SCROLL_UPDATE:
126 case ui::ET_GESTURE_SCROLL_END:
127 case ui::ET_SCROLL_FLING_START:
128 event->SetHandled();
129 break;
130 default:
131 break;
135 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
136 EventCountView::OnScrollEvent(event);
137 if (event->type() == ui::ET_SCROLL)
138 event->SetHandled();
141 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
144 // A view that implements GetMinimumSize.
145 class MinimumSizeFrameView : public NativeFrameView {
146 public:
147 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
148 virtual ~MinimumSizeFrameView() {}
150 private:
151 // Overridden from View:
152 virtual gfx::Size GetMinimumSize() const OVERRIDE {
153 return gfx::Size(300, 400);
156 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
159 // An event handler that simply keeps a count of the different types of events
160 // it receives.
161 class EventCountHandler : public ui::EventHandler {
162 public:
163 EventCountHandler() {}
164 virtual ~EventCountHandler() {}
166 int GetEventCount(ui::EventType type) {
167 return event_count_[type];
170 void ResetCounts() {
171 event_count_.clear();
174 protected:
175 // Overridden from ui::EventHandler:
176 virtual void OnEvent(ui::Event* event) OVERRIDE {
177 RecordEvent(*event);
178 ui::EventHandler::OnEvent(event);
181 private:
182 void RecordEvent(const ui::Event& event) {
183 ++event_count_[event.type()];
186 std::map<ui::EventType, int> event_count_;
188 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
191 // Class that closes the widget (which ends up deleting it immediately) when the
192 // appropriate event is received.
193 class CloseWidgetView : public View {
194 public:
195 explicit CloseWidgetView(ui::EventType event_type)
196 : event_type_(event_type) {
199 // ui::EventHandler override:
200 virtual void OnEvent(ui::Event* event) OVERRIDE {
201 if (event->type() == event_type_) {
202 // Go through NativeWidgetPrivate to simulate what happens if the OS
203 // deletes the NativeWindow out from under us.
204 GetWidget()->native_widget_private()->CloseNow();
205 } else {
206 View::OnEvent(event);
207 if (!event->IsTouchEvent())
208 event->SetHandled();
212 private:
213 const ui::EventType event_type_;
215 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
218 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
219 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
220 // because the former is implemented on all platforms but the latter is not.
221 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
222 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
223 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
224 widget->IsActive() ? ui::SHOW_STATE_NORMAL :
225 ui::SHOW_STATE_INACTIVE;
228 TEST_F(WidgetTest, WidgetInitParams) {
229 // Widgets are not transparent by default.
230 Widget::InitParams init1;
231 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
234 ////////////////////////////////////////////////////////////////////////////////
235 // Widget::GetTopLevelWidget tests.
237 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
238 // Create a hierarchy of native widgets.
239 Widget* toplevel = CreateTopLevelPlatformWidget();
240 gfx::NativeView parent = toplevel->GetNativeView();
241 Widget* child = CreateChildPlatformWidget(parent);
243 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
244 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
246 toplevel->CloseNow();
247 // |child| should be automatically destroyed with |toplevel|.
250 // Test if a focus manager and an inputmethod work without CHECK failure
251 // when window activation changes.
252 TEST_F(WidgetTest, ChangeActivation) {
253 Widget* top1 = CreateTopLevelPlatformWidget();
254 // CreateInputMethod before activated
255 top1->GetInputMethod();
256 top1->Show();
257 RunPendingMessages();
259 Widget* top2 = CreateTopLevelPlatformWidget();
260 top2->Show();
261 RunPendingMessages();
263 top1->Activate();
264 RunPendingMessages();
266 // Create InputMethod after deactivated.
267 top2->GetInputMethod();
268 top2->Activate();
269 RunPendingMessages();
271 top1->Activate();
272 RunPendingMessages();
274 top1->CloseNow();
275 top2->CloseNow();
278 // Tests visibility of child widgets.
279 TEST_F(WidgetTest, Visibility) {
280 Widget* toplevel = CreateTopLevelPlatformWidget();
281 gfx::NativeView parent = toplevel->GetNativeView();
282 Widget* child = CreateChildPlatformWidget(parent);
284 EXPECT_FALSE(toplevel->IsVisible());
285 EXPECT_FALSE(child->IsVisible());
287 child->Show();
289 EXPECT_FALSE(toplevel->IsVisible());
290 EXPECT_FALSE(child->IsVisible());
292 toplevel->Show();
294 EXPECT_TRUE(toplevel->IsVisible());
295 EXPECT_TRUE(child->IsVisible());
297 toplevel->CloseNow();
298 // |child| should be automatically destroyed with |toplevel|.
301 ////////////////////////////////////////////////////////////////////////////////
302 // Widget ownership tests.
304 // Tests various permutations of Widget ownership specified in the
305 // InitParams::Ownership param.
307 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
308 class WidgetOwnershipTest : public WidgetTest {
309 public:
310 WidgetOwnershipTest() {}
311 virtual ~WidgetOwnershipTest() {}
313 virtual void SetUp() {
314 WidgetTest::SetUp();
315 desktop_widget_ = CreateTopLevelPlatformWidget();
318 virtual void TearDown() {
319 desktop_widget_->CloseNow();
320 WidgetTest::TearDown();
323 private:
324 Widget* desktop_widget_;
326 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
329 // A bag of state to monitor destructions.
330 struct OwnershipTestState {
331 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
333 bool widget_deleted;
334 bool native_widget_deleted;
337 // A platform NativeWidget subclass that updates a bag of state when it is
338 // destroyed.
339 class OwnershipTestNativeWidget : public PlatformNativeWidget {
340 public:
341 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
342 OwnershipTestState* state)
343 : PlatformNativeWidget(delegate),
344 state_(state) {
346 virtual ~OwnershipTestNativeWidget() {
347 state_->native_widget_deleted = true;
350 private:
351 OwnershipTestState* state_;
353 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
356 // A views NativeWidget subclass that updates a bag of state when it is
357 // destroyed.
358 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
359 public:
360 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
361 OwnershipTestState* state)
362 : NativeWidgetCapture(delegate),
363 state_(state) {
365 virtual ~OwnershipTestNativeWidgetAura() {
366 state_->native_widget_deleted = true;
369 private:
370 OwnershipTestState* state_;
372 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
375 // A Widget subclass that updates a bag of state when it is destroyed.
376 class OwnershipTestWidget : public Widget {
377 public:
378 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
379 virtual ~OwnershipTestWidget() {
380 state_->widget_deleted = true;
383 private:
384 OwnershipTestState* state_;
386 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
389 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
390 // widget.
391 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
392 OwnershipTestState state;
394 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
395 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
396 params.native_widget =
397 new OwnershipTestNativeWidgetAura(widget.get(), &state);
398 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
399 widget->Init(params);
401 // Now delete the Widget, which should delete the NativeWidget.
402 widget.reset();
404 EXPECT_TRUE(state.widget_deleted);
405 EXPECT_TRUE(state.native_widget_deleted);
407 // TODO(beng): write test for this ownership scenario and the NativeWidget
408 // being deleted out from under the Widget.
411 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
412 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
413 OwnershipTestState state;
415 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
416 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
417 params.native_widget =
418 new OwnershipTestNativeWidgetAura(widget.get(), &state);
419 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
420 widget->Init(params);
422 // Now delete the Widget, which should delete the NativeWidget.
423 widget.reset();
425 EXPECT_TRUE(state.widget_deleted);
426 EXPECT_TRUE(state.native_widget_deleted);
428 // TODO(beng): write test for this ownership scenario and the NativeWidget
429 // being deleted out from under the Widget.
432 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
433 // destroy the parent view.
434 TEST_F(WidgetOwnershipTest,
435 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
436 OwnershipTestState state;
438 Widget* toplevel = CreateTopLevelPlatformWidget();
440 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
441 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
442 params.native_widget =
443 new OwnershipTestNativeWidgetAura(widget.get(), &state);
444 params.parent = toplevel->GetNativeView();
445 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
446 widget->Init(params);
448 // Now close the toplevel, which deletes the view hierarchy.
449 toplevel->CloseNow();
451 RunPendingMessages();
453 // This shouldn't delete the widget because it shouldn't be deleted
454 // from the native side.
455 EXPECT_FALSE(state.widget_deleted);
456 EXPECT_FALSE(state.native_widget_deleted);
458 // Now delete it explicitly.
459 widget.reset();
461 EXPECT_TRUE(state.widget_deleted);
462 EXPECT_TRUE(state.native_widget_deleted);
465 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
466 // widget.
467 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
468 OwnershipTestState state;
470 Widget* widget = new OwnershipTestWidget(&state);
471 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
472 params.native_widget =
473 new OwnershipTestNativeWidgetAura(widget, &state);
474 widget->Init(params);
476 // Now destroy the native widget.
477 widget->CloseNow();
479 EXPECT_TRUE(state.widget_deleted);
480 EXPECT_TRUE(state.native_widget_deleted);
483 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
484 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
485 OwnershipTestState state;
487 Widget* toplevel = CreateTopLevelPlatformWidget();
489 Widget* widget = new OwnershipTestWidget(&state);
490 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
491 params.native_widget =
492 new OwnershipTestNativeWidgetAura(widget, &state);
493 params.parent = toplevel->GetNativeView();
494 widget->Init(params);
496 // Now destroy the native widget. This is achieved by closing the toplevel.
497 toplevel->CloseNow();
499 // The NativeWidget won't be deleted until after a return to the message loop
500 // so we have to run pending messages before testing the destruction status.
501 RunPendingMessages();
503 EXPECT_TRUE(state.widget_deleted);
504 EXPECT_TRUE(state.native_widget_deleted);
507 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
508 // widget, destroyed out from under it by the OS.
509 TEST_F(WidgetOwnershipTest,
510 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
511 OwnershipTestState state;
513 Widget* widget = new OwnershipTestWidget(&state);
514 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
515 params.native_widget =
516 new OwnershipTestNativeWidgetAura(widget, &state);
517 widget->Init(params);
519 // Now simulate a destroy of the platform native widget from the OS:
520 SimulateNativeDestroy(widget);
522 EXPECT_TRUE(state.widget_deleted);
523 EXPECT_TRUE(state.native_widget_deleted);
526 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
527 // destroyed by the view hierarchy that contains it.
528 TEST_F(WidgetOwnershipTest,
529 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
530 OwnershipTestState state;
532 Widget* toplevel = CreateTopLevelPlatformWidget();
534 Widget* widget = new OwnershipTestWidget(&state);
535 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
536 params.native_widget =
537 new OwnershipTestNativeWidgetAura(widget, &state);
538 params.parent = toplevel->GetNativeView();
539 widget->Init(params);
541 // Destroy the widget (achieved by closing the toplevel).
542 toplevel->CloseNow();
544 // The NativeWidget won't be deleted until after a return to the message loop
545 // so we have to run pending messages before testing the destruction status.
546 RunPendingMessages();
548 EXPECT_TRUE(state.widget_deleted);
549 EXPECT_TRUE(state.native_widget_deleted);
552 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
553 // we close it directly.
554 TEST_F(WidgetOwnershipTest,
555 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
556 OwnershipTestState state;
558 Widget* toplevel = CreateTopLevelPlatformWidget();
560 Widget* widget = new OwnershipTestWidget(&state);
561 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
562 params.native_widget =
563 new OwnershipTestNativeWidgetAura(widget, &state);
564 params.parent = toplevel->GetNativeView();
565 widget->Init(params);
567 // Destroy the widget.
568 widget->Close();
569 toplevel->CloseNow();
571 // The NativeWidget won't be deleted until after a return to the message loop
572 // so we have to run pending messages before testing the destruction status.
573 RunPendingMessages();
575 EXPECT_TRUE(state.widget_deleted);
576 EXPECT_TRUE(state.native_widget_deleted);
579 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
580 TEST_F(WidgetOwnershipTest,
581 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
582 OwnershipTestState state;
584 WidgetDelegateView* delegate_view = new WidgetDelegateView;
586 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
587 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
588 params.native_widget =
589 new OwnershipTestNativeWidgetAura(widget.get(), &state);
590 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
591 params.delegate = delegate_view;
592 widget->Init(params);
593 widget->SetContentsView(delegate_view);
595 // Now delete the Widget. There should be no crash or use-after-free.
596 widget.reset();
598 EXPECT_TRUE(state.widget_deleted);
599 EXPECT_TRUE(state.native_widget_deleted);
602 ////////////////////////////////////////////////////////////////////////////////
603 // Test to verify using various Widget methods doesn't crash when the underlying
604 // NativeView is destroyed.
606 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
607 public:
608 WidgetWithDestroyedNativeViewTest() {}
609 virtual ~WidgetWithDestroyedNativeViewTest() {}
611 void InvokeWidgetMethods(Widget* widget) {
612 widget->GetNativeView();
613 widget->GetNativeWindow();
614 ui::Accelerator accelerator;
615 widget->GetAccelerator(0, &accelerator);
616 widget->GetTopLevelWidget();
617 widget->GetWindowBoundsInScreen();
618 widget->GetClientAreaBoundsInScreen();
619 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
620 widget->SetSize(gfx::Size(10, 11));
621 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
622 widget->SetVisibilityChangedAnimationsEnabled(false);
623 widget->StackAtTop();
624 widget->IsClosed();
625 widget->Close();
626 widget->Hide();
627 widget->Activate();
628 widget->Deactivate();
629 widget->IsActive();
630 widget->DisableInactiveRendering();
631 widget->SetAlwaysOnTop(true);
632 widget->IsAlwaysOnTop();
633 widget->Maximize();
634 widget->Minimize();
635 widget->Restore();
636 widget->IsMaximized();
637 widget->IsFullscreen();
638 widget->SetOpacity(0);
639 widget->SetUseDragFrame(true);
640 widget->FlashFrame(true);
641 widget->IsVisible();
642 widget->GetThemeProvider();
643 widget->GetNativeTheme();
644 widget->GetFocusManager();
645 widget->GetInputMethod();
646 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
647 widget->IsMouseEventsEnabled();
648 widget->SetNativeWindowProperty("xx", widget);
649 widget->GetNativeWindowProperty("xx");
650 widget->GetFocusTraversable();
651 widget->GetLayer();
652 widget->ReorderNativeViews();
653 widget->SetCapture(widget->GetRootView());
654 widget->ReleaseCapture();
655 widget->HasCapture();
656 widget->GetWorkAreaBoundsInScreen();
657 widget->IsTranslucentWindowOpacitySupported();
660 private:
661 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
664 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
666 Widget widget;
667 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
668 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
669 widget.Init(params);
670 widget.Show();
672 widget.native_widget_private()->CloseNow();
673 InvokeWidgetMethods(&widget);
675 #if !defined(OS_CHROMEOS)
677 Widget widget;
678 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
679 params.native_widget = new PlatformDesktopNativeWidget(&widget);
680 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
681 widget.Init(params);
682 widget.Show();
684 widget.native_widget_private()->CloseNow();
685 InvokeWidgetMethods(&widget);
687 #endif
690 ////////////////////////////////////////////////////////////////////////////////
691 // Widget observer tests.
694 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
695 public:
696 WidgetObserverTest()
697 : active_(NULL),
698 widget_closed_(NULL),
699 widget_activated_(NULL),
700 widget_shown_(NULL),
701 widget_hidden_(NULL),
702 widget_bounds_changed_(NULL) {
705 virtual ~WidgetObserverTest() {}
707 // Overridden from WidgetObserver:
708 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
709 if (active_ == widget)
710 active_ = NULL;
711 widget_closed_ = widget;
714 virtual void OnWidgetActivationChanged(Widget* widget,
715 bool active) OVERRIDE {
716 if (active) {
717 if (widget_activated_)
718 widget_activated_->Deactivate();
719 widget_activated_ = widget;
720 active_ = widget;
721 } else {
722 if (widget_activated_ == widget)
723 widget_activated_ = NULL;
724 widget_deactivated_ = widget;
728 virtual void OnWidgetVisibilityChanged(Widget* widget,
729 bool visible) OVERRIDE {
730 if (visible)
731 widget_shown_ = widget;
732 else
733 widget_hidden_ = widget;
736 virtual void OnWidgetBoundsChanged(Widget* widget,
737 const gfx::Rect& new_bounds) OVERRIDE {
738 widget_bounds_changed_ = widget;
741 void reset() {
742 active_ = NULL;
743 widget_closed_ = NULL;
744 widget_activated_ = NULL;
745 widget_deactivated_ = NULL;
746 widget_shown_ = NULL;
747 widget_hidden_ = NULL;
748 widget_bounds_changed_ = NULL;
751 Widget* NewWidget() {
752 Widget* widget = CreateTopLevelNativeWidget();
753 widget->AddObserver(this);
754 return widget;
757 const Widget* active() const { return active_; }
758 const Widget* widget_closed() const { return widget_closed_; }
759 const Widget* widget_activated() const { return widget_activated_; }
760 const Widget* widget_deactivated() const { return widget_deactivated_; }
761 const Widget* widget_shown() const { return widget_shown_; }
762 const Widget* widget_hidden() const { return widget_hidden_; }
763 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
765 private:
766 Widget* active_;
768 Widget* widget_closed_;
769 Widget* widget_activated_;
770 Widget* widget_deactivated_;
771 Widget* widget_shown_;
772 Widget* widget_hidden_;
773 Widget* widget_bounds_changed_;
776 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
777 Widget* toplevel = CreateTopLevelPlatformWidget();
779 Widget* toplevel1 = NewWidget();
780 Widget* toplevel2 = NewWidget();
782 toplevel1->Show();
783 toplevel2->Show();
785 reset();
787 toplevel1->Activate();
789 RunPendingMessages();
790 EXPECT_EQ(toplevel1, widget_activated());
792 toplevel2->Activate();
793 RunPendingMessages();
794 EXPECT_EQ(toplevel1, widget_deactivated());
795 EXPECT_EQ(toplevel2, widget_activated());
796 EXPECT_EQ(toplevel2, active());
798 toplevel->CloseNow();
801 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
802 Widget* toplevel = CreateTopLevelPlatformWidget();
804 Widget* child1 = NewWidget();
805 Widget* child2 = NewWidget();
807 toplevel->Show();
808 child1->Show();
809 child2->Show();
811 reset();
813 child1->Hide();
814 EXPECT_EQ(child1, widget_hidden());
816 child2->Hide();
817 EXPECT_EQ(child2, widget_hidden());
819 child1->Show();
820 EXPECT_EQ(child1, widget_shown());
822 child2->Show();
823 EXPECT_EQ(child2, widget_shown());
825 toplevel->CloseNow();
828 TEST_F(WidgetObserverTest, DestroyBubble) {
829 Widget* anchor = CreateTopLevelPlatformWidget();
830 anchor->Show();
832 BubbleDelegateView* bubble_delegate =
833 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
834 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
835 bubble_widget->Show();
836 bubble_widget->CloseNow();
838 anchor->Hide();
839 anchor->CloseNow();
842 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
843 Widget* child1 = NewWidget();
844 Widget* child2 = NewWidget();
846 child1->OnNativeWidgetMove();
847 EXPECT_EQ(child1, widget_bounds_changed());
849 child2->OnNativeWidgetMove();
850 EXPECT_EQ(child2, widget_bounds_changed());
852 child1->OnNativeWidgetSizeChanged(gfx::Size());
853 EXPECT_EQ(child1, widget_bounds_changed());
855 child2->OnNativeWidgetSizeChanged(gfx::Size());
856 EXPECT_EQ(child2, widget_bounds_changed());
859 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
860 // widget is visible and not maximized or fullscreen.
861 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
862 // Choose test coordinates away from edges and dimensions that are "small"
863 // (but not too small) to ensure the OS doesn't try to adjust them.
864 const gfx::Rect kTestBounds(150, 150, 400, 300);
865 const gfx::Size kTestSize(200, 180);
867 // First test a toplevel widget.
868 Widget* widget = CreateTopLevelPlatformWidget();
869 widget->Show();
871 EXPECT_NE(kTestSize.ToString(),
872 widget->GetWindowBoundsInScreen().size().ToString());
873 widget->SetSize(kTestSize);
874 EXPECT_EQ(kTestSize.ToString(),
875 widget->GetWindowBoundsInScreen().size().ToString());
877 EXPECT_NE(kTestBounds.ToString(),
878 widget->GetWindowBoundsInScreen().ToString());
879 widget->SetBounds(kTestBounds);
880 EXPECT_EQ(kTestBounds.ToString(),
881 widget->GetWindowBoundsInScreen().ToString());
883 // Changing just the size should not change the origin.
884 widget->SetSize(kTestSize);
885 EXPECT_EQ(kTestBounds.origin().ToString(),
886 widget->GetWindowBoundsInScreen().origin().ToString());
888 widget->CloseNow();
890 // Same tests with a frameless window.
891 widget = CreateTopLevelFramelessPlatformWidget();
892 widget->Show();
894 EXPECT_NE(kTestSize.ToString(),
895 widget->GetWindowBoundsInScreen().size().ToString());
896 widget->SetSize(kTestSize);
897 EXPECT_EQ(kTestSize.ToString(),
898 widget->GetWindowBoundsInScreen().size().ToString());
900 EXPECT_NE(kTestBounds.ToString(),
901 widget->GetWindowBoundsInScreen().ToString());
902 widget->SetBounds(kTestBounds);
903 EXPECT_EQ(kTestBounds.ToString(),
904 widget->GetWindowBoundsInScreen().ToString());
906 // For a frameless widget, the client bounds should also match.
907 EXPECT_EQ(kTestBounds.ToString(),
908 widget->GetClientAreaBoundsInScreen().ToString());
910 // Verify origin is stable for a frameless window as well.
911 widget->SetSize(kTestSize);
912 EXPECT_EQ(kTestBounds.origin().ToString(),
913 widget->GetWindowBoundsInScreen().origin().ToString());
915 widget->CloseNow();
918 #if defined(false)
919 // Aura needs shell to maximize/fullscreen window.
920 // NativeWidgetGtk doesn't implement GetRestoredBounds.
921 TEST_F(WidgetTest, GetRestoredBounds) {
922 Widget* toplevel = CreateTopLevelPlatformWidget();
923 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
924 toplevel->GetRestoredBounds().ToString());
925 toplevel->Show();
926 toplevel->Maximize();
927 RunPendingMessages();
928 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
929 toplevel->GetRestoredBounds().ToString());
930 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
931 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
933 toplevel->Restore();
934 RunPendingMessages();
935 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
936 toplevel->GetRestoredBounds().ToString());
938 toplevel->SetFullscreen(true);
939 RunPendingMessages();
940 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
941 toplevel->GetRestoredBounds().ToString());
942 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
943 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
945 #endif
947 // Test that window state is not changed after getting out of full screen.
948 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
949 Widget* toplevel = CreateTopLevelPlatformWidget();
951 toplevel->Show();
952 RunPendingMessages();
954 // This should be a normal state window.
955 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
957 toplevel->SetFullscreen(true);
958 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
959 toplevel->SetFullscreen(false);
960 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
962 // And it should still be in normal state after getting out of full screen.
963 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
965 // Now, make it maximized.
966 toplevel->Maximize();
967 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
969 toplevel->SetFullscreen(true);
970 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
971 toplevel->SetFullscreen(false);
972 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
974 // And it stays maximized after getting out of full screen.
975 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
977 // Clean up.
978 toplevel->Close();
979 RunPendingMessages();
982 // The key-event propagation from Widget happens differently on aura and
983 // non-aura systems because of the difference in IME. So this test works only on
984 // aura.
985 TEST_F(WidgetTest, KeyboardInputEvent) {
986 Widget* toplevel = CreateTopLevelPlatformWidget();
987 View* container = toplevel->client_view();
989 Textfield* textfield = new Textfield();
990 textfield->SetText(base::ASCIIToUTF16("some text"));
991 container->AddChildView(textfield);
992 toplevel->Show();
993 textfield->RequestFocus();
995 // The press gets handled. The release doesn't have an effect.
996 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
997 toplevel->OnKeyEvent(&backspace_p);
998 EXPECT_TRUE(backspace_p.stopped_propagation());
999 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1000 toplevel->OnKeyEvent(&backspace_r);
1001 EXPECT_FALSE(backspace_r.handled());
1003 toplevel->Close();
1006 // Verifies bubbles result in a focus lost when shown.
1007 // TODO(msw): this tests relies on focus, it needs to be in
1008 // interactive_ui_tests.
1009 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1010 // Create a widget, show and activate it and focus the contents view.
1011 View* contents_view = new View;
1012 contents_view->SetFocusable(true);
1013 Widget widget;
1014 Widget::InitParams init_params =
1015 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1016 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1017 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1018 #if !defined(OS_CHROMEOS)
1019 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1020 #endif
1021 widget.Init(init_params);
1022 widget.SetContentsView(contents_view);
1023 widget.Show();
1024 widget.Activate();
1025 contents_view->RequestFocus();
1026 EXPECT_TRUE(contents_view->HasFocus());
1028 // Show a bubble.
1029 BubbleDelegateView* bubble_delegate_view =
1030 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1031 bubble_delegate_view->SetFocusable(true);
1032 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1033 bubble_delegate_view->RequestFocus();
1035 // |contents_view_| should no longer have focus.
1036 EXPECT_FALSE(contents_view->HasFocus());
1037 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1039 bubble_delegate_view->GetWidget()->CloseNow();
1041 // Closing the bubble should result in focus going back to the contents view.
1042 EXPECT_TRUE(contents_view->HasFocus());
1045 class TestBubbleDelegateView : public BubbleDelegateView {
1046 public:
1047 TestBubbleDelegateView(View* anchor)
1048 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1049 reset_controls_called_(false) {}
1050 virtual ~TestBubbleDelegateView() {}
1052 virtual bool ShouldShowCloseButton() const OVERRIDE {
1053 reset_controls_called_ = true;
1054 return true;
1057 mutable bool reset_controls_called_;
1060 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1061 Widget* anchor = CreateTopLevelPlatformWidget();
1062 anchor->Show();
1064 TestBubbleDelegateView* bubble_delegate =
1065 new TestBubbleDelegateView(anchor->client_view());
1066 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1067 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1068 bubble_widget->Show();
1069 bubble_widget->CloseNow();
1071 anchor->Hide();
1072 anchor->CloseNow();
1075 // Desktop native widget Aura tests are for non Chrome OS platforms.
1076 #if !defined(OS_CHROMEOS)
1077 // Test to ensure that after minimize, view width is set to zero.
1078 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1079 // Create a widget.
1080 Widget widget;
1081 Widget::InitParams init_params =
1082 CreateParams(Widget::InitParams::TYPE_WINDOW);
1083 init_params.show_state = ui::SHOW_STATE_NORMAL;
1084 gfx::Rect initial_bounds(0, 0, 300, 400);
1085 init_params.bounds = initial_bounds;
1086 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1087 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1088 widget.Init(init_params);
1089 NonClientView* non_client_view = widget.non_client_view();
1090 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1091 non_client_view->SetFrameView(frame_view);
1092 widget.Show();
1093 widget.Minimize();
1094 EXPECT_EQ(0, frame_view->width());
1097 // This class validates whether paints are received for a visible Widget.
1098 // To achieve this it overrides the Show and Close methods on the Widget class
1099 // and sets state whether subsequent paints are expected.
1100 class DesktopAuraTestValidPaintWidget : public views::Widget {
1101 public:
1102 DesktopAuraTestValidPaintWidget()
1103 : expect_paint_(true),
1104 received_paint_while_hidden_(false) {
1107 virtual ~DesktopAuraTestValidPaintWidget() {
1110 virtual void Show() OVERRIDE {
1111 expect_paint_ = true;
1112 views::Widget::Show();
1115 virtual void Close() OVERRIDE {
1116 expect_paint_ = false;
1117 views::Widget::Close();
1120 void Hide() {
1121 expect_paint_ = false;
1122 views::Widget::Hide();
1125 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1126 EXPECT_TRUE(expect_paint_);
1127 if (!expect_paint_)
1128 received_paint_while_hidden_ = true;
1129 views::Widget::OnNativeWidgetPaint(canvas);
1132 bool received_paint_while_hidden() const {
1133 return received_paint_while_hidden_;
1136 private:
1137 bool expect_paint_;
1138 bool received_paint_while_hidden_;
1141 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1142 View* contents_view = new View;
1143 contents_view->SetFocusable(true);
1144 DesktopAuraTestValidPaintWidget widget;
1145 Widget::InitParams init_params =
1146 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1147 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1148 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1149 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1150 widget.Init(init_params);
1151 widget.SetContentsView(contents_view);
1152 widget.Show();
1153 widget.Activate();
1154 RunPendingMessages();
1155 widget.SchedulePaintInRect(init_params.bounds);
1156 widget.Close();
1157 RunPendingMessages();
1158 EXPECT_FALSE(widget.received_paint_while_hidden());
1161 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1162 View* contents_view = new View;
1163 contents_view->SetFocusable(true);
1164 DesktopAuraTestValidPaintWidget widget;
1165 Widget::InitParams init_params =
1166 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1167 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1168 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1169 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1170 widget.Init(init_params);
1171 widget.SetContentsView(contents_view);
1172 widget.Show();
1173 widget.Activate();
1174 RunPendingMessages();
1175 widget.SchedulePaintInRect(init_params.bounds);
1176 widget.Hide();
1177 RunPendingMessages();
1178 EXPECT_FALSE(widget.received_paint_while_hidden());
1179 widget.Close();
1182 // Test to ensure that the aura Window's visiblity state is set to visible if
1183 // the underlying widget is hidden and then shown.
1184 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1185 // Create a widget.
1186 Widget widget;
1187 Widget::InitParams init_params =
1188 CreateParams(Widget::InitParams::TYPE_WINDOW);
1189 init_params.show_state = ui::SHOW_STATE_NORMAL;
1190 gfx::Rect initial_bounds(0, 0, 300, 400);
1191 init_params.bounds = initial_bounds;
1192 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1193 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1194 widget.Init(init_params);
1195 NonClientView* non_client_view = widget.non_client_view();
1196 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1197 non_client_view->SetFrameView(frame_view);
1199 widget.Hide();
1200 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1201 widget.Show();
1202 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1205 // The following code verifies we can correctly destroy a Widget from a mouse
1206 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1207 // nested message loops from such events, nor has the code ever really dealt
1208 // with this situation.
1210 // Generates two moves (first generates enter, second real move), a press, drag
1211 // and release stopping at |last_event_type|.
1212 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1213 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1214 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1215 screen_bounds.CenterPoint(), 0, 0);
1216 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1217 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1218 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1219 return;
1220 details = dispatcher->OnEventFromSource(&move_event);
1221 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1222 return;
1224 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1225 screen_bounds.CenterPoint(), 0, 0);
1226 details = dispatcher->OnEventFromSource(&press_event);
1227 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1228 return;
1230 gfx::Point end_point(screen_bounds.CenterPoint());
1231 end_point.Offset(1, 1);
1232 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1233 details = dispatcher->OnEventFromSource(&drag_event);
1234 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1235 return;
1237 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1239 details = dispatcher->OnEventFromSource(&release_event);
1240 if (details.dispatcher_destroyed)
1241 return;
1244 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1245 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1246 ui::EventType last_event_type) {
1247 // |widget| is deleted by CloseWidgetView.
1248 Widget* widget = new Widget;
1249 Widget::InitParams params =
1250 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1251 params.native_widget = new PlatformDesktopNativeWidget(widget);
1252 params.bounds = gfx::Rect(0, 0, 50, 100);
1253 widget->Init(params);
1254 widget->SetContentsView(new CloseWidgetView(last_event_type));
1255 widget->Show();
1256 GenerateMouseEvents(widget, last_event_type);
1259 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1260 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1261 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1264 // Verifies deleting the widget from a mouse released event doesn't crash.
1265 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1266 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1269 #endif // !defined(OS_CHROMEOS)
1271 // Tests that wheel events generated from scroll events are targetted to the
1272 // views under the cursor when the focused view does not processed them.
1273 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1274 EventCountView* cursor_view = new EventCountView;
1275 cursor_view->SetBounds(60, 0, 50, 40);
1277 Widget* widget = CreateTopLevelPlatformWidget();
1278 widget->GetRootView()->AddChildView(cursor_view);
1280 // Generate a scroll event on the cursor view.
1281 ui::ScrollEvent scroll(ui::ET_SCROLL,
1282 gfx::Point(65, 5),
1283 ui::EventTimeForNow(),
1285 0, 20,
1286 0, 20,
1288 widget->OnScrollEvent(&scroll);
1290 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1291 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1293 cursor_view->ResetCounts();
1295 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1296 gfx::Point(5, 5),
1297 ui::EventTimeForNow(),
1299 0, 20,
1300 0, 20,
1302 widget->OnScrollEvent(&scroll2);
1304 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1305 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1307 widget->CloseNow();
1310 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1311 // events are not dispatched to any view.
1312 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1313 EventCountView* noscroll_view = new EventCountView;
1314 EventCountView* scroll_view = new ScrollableEventCountView;
1316 noscroll_view->SetBounds(0, 0, 50, 40);
1317 scroll_view->SetBounds(60, 0, 40, 40);
1319 Widget* widget = CreateTopLevelPlatformWidget();
1320 widget->GetRootView()->AddChildView(noscroll_view);
1321 widget->GetRootView()->AddChildView(scroll_view);
1324 ui::GestureEvent begin(
1328 base::TimeDelta(),
1329 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
1330 widget->OnGestureEvent(&begin);
1331 ui::GestureEvent update(
1335 base::TimeDelta(),
1336 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1337 widget->OnGestureEvent(&update);
1338 ui::GestureEvent end(
1342 base::TimeDelta(),
1343 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0));
1344 widget->OnGestureEvent(&end);
1346 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1347 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1348 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1352 ui::GestureEvent begin(
1356 base::TimeDelta(),
1357 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
1358 widget->OnGestureEvent(&begin);
1359 ui::GestureEvent update(
1363 base::TimeDelta(),
1364 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1365 widget->OnGestureEvent(&update);
1366 ui::GestureEvent end(
1370 base::TimeDelta(),
1371 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0));
1372 widget->OnGestureEvent(&end);
1374 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1375 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1376 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1379 widget->CloseNow();
1382 // Tests that event-handlers installed on the RootView get triggered correctly.
1383 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1384 TEST_F(WidgetTest, EventHandlersOnRootView) {
1385 Widget* widget = CreateTopLevelNativeWidget();
1386 View* root_view = widget->GetRootView();
1388 scoped_ptr<EventCountView> view(new EventCountView());
1389 view->set_owned_by_client();
1390 view->SetBounds(0, 0, 20, 20);
1391 root_view->AddChildView(view.get());
1393 EventCountHandler h1;
1394 root_view->AddPreTargetHandler(&h1);
1396 EventCountHandler h2;
1397 root_view->AddPostTargetHandler(&h2);
1399 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1400 widget->Show();
1402 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1403 // bubble up the views hierarchy to be re-dispatched on the root view.
1404 ui::ScrollEvent scroll(ui::ET_SCROLL,
1405 gfx::Point(5, 5),
1406 ui::EventTimeForNow(),
1408 0, 20,
1409 0, 20,
1411 widget->OnScrollEvent(&scroll);
1412 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1413 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1414 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1416 // Unhandled scroll events are turned into wheel events and re-dispatched.
1417 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1418 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1419 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1421 h1.ResetCounts();
1422 view->ResetCounts();
1423 h2.ResetCounts();
1425 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1426 // should bubble up the views hierarchy to be re-dispatched on the root view.
1427 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1428 gfx::Point(5, 5),
1429 ui::EventTimeForNow(),
1431 0, 20,
1432 0, 20,
1434 widget->OnScrollEvent(&fling);
1435 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1436 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1437 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1439 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1440 // be turned into wheel events and re-dispatched.
1441 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1442 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1443 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1445 h1.ResetCounts();
1446 view->ResetCounts();
1447 h2.ResetCounts();
1449 // Change the handle mode of |view| so that events are marked as handled at
1450 // the target phase.
1451 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1453 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1454 // The events are handled at the target phase and should not reach the
1455 // post-target handler.
1456 ui::GestureEvent tap_down(5,
1459 ui::EventTimeForNow(),
1460 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN,
1462 0));
1463 widget->OnGestureEvent(&tap_down);
1464 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1465 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1466 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1468 ui::GestureEvent tap_cancel(5,
1471 ui::EventTimeForNow(),
1472 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL,
1474 0));
1475 widget->OnGestureEvent(&tap_cancel);
1476 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1477 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1478 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1480 h1.ResetCounts();
1481 view->ResetCounts();
1482 h2.ResetCounts();
1484 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1485 // and should not reach the post-target handler.
1486 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1487 gfx::Point(5, 5),
1488 ui::EventTimeForNow(),
1490 0, 20,
1491 0, 20,
1493 widget->OnScrollEvent(&consumed_scroll);
1494 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1495 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1496 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1498 // Handled scroll events are not turned into wheel events and re-dispatched.
1499 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1500 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1501 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1503 widget->CloseNow();
1506 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1507 Widget* widget = CreateTopLevelNativeWidget();
1508 View* root_view = widget->GetRootView();
1510 EventCountView* v1 = new EventCountView();
1511 v1->SetBounds(0, 0, 10, 10);
1512 root_view->AddChildView(v1);
1513 EventCountView* v2 = new EventCountView();
1514 v2->SetBounds(0, 10, 10, 10);
1515 root_view->AddChildView(v2);
1517 gfx::Point cursor_location(5, 5);
1518 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1519 ui::EF_NONE, ui::EF_NONE);
1520 widget->OnMouseEvent(&move);
1522 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1523 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1525 delete v1;
1526 v2->SetBounds(0, 0, 10, 10);
1527 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1529 widget->SynthesizeMouseMoveEvent();
1530 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1533 namespace {
1535 // ui::EventHandler which handles all mouse press events.
1536 class MousePressEventConsumer : public ui::EventHandler {
1537 public:
1538 explicit MousePressEventConsumer() {
1541 virtual ~MousePressEventConsumer() {
1544 private:
1545 // ui::EventHandler:
1546 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1547 if (event->type() == ui::ET_MOUSE_PRESSED)
1548 event->SetHandled();
1551 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1554 } // namespace
1556 // Test that mouse presses and mouse releases are dispatched normally when a
1557 // touch is down.
1558 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1559 Widget* widget = CreateTopLevelNativeWidget();
1560 widget->Show();
1561 widget->SetSize(gfx::Size(300, 300));
1563 EventCountView* event_count_view = new EventCountView();
1564 event_count_view->SetBounds(0, 0, 300, 300);
1565 widget->GetRootView()->AddChildView(event_count_view);
1567 MousePressEventConsumer consumer;
1568 event_count_view->AddPostTargetHandler(&consumer);
1570 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1571 generator.PressTouch();
1572 generator.ClickLeftButton();
1574 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1575 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1577 widget->CloseNow();
1580 // Used by SingleWindowClosing to count number of times WindowClosing() has
1581 // been invoked.
1582 class ClosingDelegate : public WidgetDelegate {
1583 public:
1584 ClosingDelegate() : count_(0), widget_(NULL) {}
1586 int count() const { return count_; }
1588 void set_widget(views::Widget* widget) { widget_ = widget; }
1590 // WidgetDelegate overrides:
1591 virtual Widget* GetWidget() OVERRIDE { return widget_; }
1592 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
1593 virtual void WindowClosing() OVERRIDE {
1594 count_++;
1597 private:
1598 int count_;
1599 views::Widget* widget_;
1601 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1604 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1605 // is closed.
1606 TEST_F(WidgetTest, SingleWindowClosing) {
1607 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1608 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1609 Widget::InitParams init_params =
1610 CreateParams(Widget::InitParams::TYPE_WINDOW);
1611 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1612 init_params.delegate = delegate.get();
1613 #if !defined(OS_CHROMEOS)
1614 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1615 #endif
1616 widget->Init(init_params);
1617 EXPECT_EQ(0, delegate->count());
1618 widget->CloseNow();
1619 EXPECT_EQ(1, delegate->count());
1622 class WidgetWindowTitleTest : public WidgetTest {
1623 protected:
1624 void RunTest(bool desktop_native_widget) {
1625 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1626 Widget::InitParams init_params =
1627 CreateParams(Widget::InitParams::TYPE_WINDOW);
1628 widget->Init(init_params);
1630 #if !defined(OS_CHROMEOS)
1631 if (desktop_native_widget)
1632 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1633 #else
1634 DCHECK(!desktop_native_widget)
1635 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1636 #endif
1638 internal::NativeWidgetPrivate* native_widget =
1639 widget->native_widget_private();
1641 base::string16 empty;
1642 base::string16 s1(base::UTF8ToUTF16("Title1"));
1643 base::string16 s2(base::UTF8ToUTF16("Title2"));
1644 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1646 // The widget starts with no title, setting empty should not change
1647 // anything.
1648 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1649 // Setting the title to something non-empty should cause a change.
1650 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1651 // Setting the title to something else with the same length should cause a
1652 // change.
1653 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1654 // Setting the title to something else with a different length should cause
1655 // a change.
1656 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1657 // Setting the title to the same thing twice should not cause a change.
1658 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1660 widget->CloseNow();
1664 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1665 // Use the default NativeWidget.
1666 bool desktop_native_widget = false;
1667 RunTest(desktop_native_widget);
1670 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1671 #if !defined(OS_CHROMEOS)
1672 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1673 // Override to use a DesktopNativeWidget.
1674 bool desktop_native_widget = true;
1675 RunTest(desktop_native_widget);
1677 #endif // !OS_CHROMEOS
1679 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1680 Widget* widget = new Widget;
1681 Widget::InitParams params =
1682 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1683 widget->Init(params);
1685 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1687 widget->SetSize(gfx::Size(100, 100));
1688 widget->Show();
1690 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1692 WidgetDeletionObserver deletion_observer(widget);
1693 generator.ClickLeftButton();
1694 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1696 // Yay we did not crash!
1699 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1700 Widget* widget = new Widget;
1701 Widget::InitParams params =
1702 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1703 widget->Init(params);
1705 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1707 widget->SetSize(gfx::Size(100, 100));
1708 widget->Show();
1710 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1712 WidgetDeletionObserver deletion_observer(widget);
1713 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1714 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1716 // Yay we did not crash!
1719 // See description of RunGetNativeThemeFromDestructor() for details.
1720 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1721 public:
1722 GetNativeThemeFromDestructorView() {}
1723 virtual ~GetNativeThemeFromDestructorView() {
1724 VerifyNativeTheme();
1727 virtual View* GetContentsView() OVERRIDE {
1728 return this;
1731 private:
1732 void VerifyNativeTheme() {
1733 ASSERT_TRUE(GetNativeTheme() != NULL);
1736 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1739 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1740 // crash. |is_first_run| is true if this is the first call. A return value of
1741 // true indicates this should be run again with a value of false.
1742 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1743 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1744 bool is_first_run) {
1745 bool needs_second_run = false;
1746 // Destroyed by CloseNow() below.
1747 Widget* widget = new Widget;
1748 Widget::InitParams params(in_params);
1749 // Deletes itself when the Widget is destroyed.
1750 params.delegate = new GetNativeThemeFromDestructorView;
1751 #if !defined(OS_CHROMEOS)
1752 if (is_first_run) {
1753 params.native_widget = new PlatformDesktopNativeWidget(widget);
1754 needs_second_run = true;
1756 #endif
1757 widget->Init(params);
1758 widget->CloseNow();
1759 return needs_second_run;
1762 // See description of RunGetNativeThemeFromDestructor() for details.
1763 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1764 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1765 if (RunGetNativeThemeFromDestructor(params, true))
1766 RunGetNativeThemeFromDestructor(params, false);
1769 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1770 // destroyed.
1771 class CloseDestroysWidget : public Widget {
1772 public:
1773 explicit CloseDestroysWidget(bool* destroyed)
1774 : destroyed_(destroyed) {
1777 virtual ~CloseDestroysWidget() {
1778 if (destroyed_) {
1779 *destroyed_ = true;
1780 base::MessageLoop::current()->QuitNow();
1784 void Detach() { destroyed_ = NULL; }
1786 private:
1787 // If non-null set to true from destructor.
1788 bool* destroyed_;
1790 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1793 // An observer that registers that an animation has ended.
1794 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1795 public:
1796 AnimationEndObserver() : animation_completed_(false) {}
1797 virtual ~AnimationEndObserver() {}
1799 bool animation_completed() const { return animation_completed_; }
1801 // ui::ImplicitAnimationObserver:
1802 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
1803 animation_completed_ = true;
1806 private:
1807 bool animation_completed_;
1809 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1812 // An observer that registers the bounds of a widget on destruction.
1813 class WidgetBoundsObserver : public WidgetObserver {
1814 public:
1815 WidgetBoundsObserver() {}
1816 virtual ~WidgetBoundsObserver() {}
1818 gfx::Rect bounds() { return bounds_; }
1820 // WidgetObserver:
1821 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
1822 bounds_ = widget->GetWindowBoundsInScreen();
1825 private:
1826 gfx::Rect bounds_;
1828 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1831 // Verifies Close() results in destroying.
1832 TEST_F(WidgetTest, CloseDestroys) {
1833 bool destroyed = false;
1834 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1835 Widget::InitParams params =
1836 CreateParams(views::Widget::InitParams::TYPE_MENU);
1837 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1838 #if !defined(OS_CHROMEOS)
1839 params.native_widget = new PlatformDesktopNativeWidget(widget);
1840 #endif
1841 widget->Init(params);
1842 widget->Show();
1843 widget->Hide();
1844 widget->Close();
1845 EXPECT_FALSE(destroyed);
1846 // Run the message loop as Close() asynchronously deletes.
1847 base::RunLoop().Run();
1848 EXPECT_TRUE(destroyed);
1849 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1850 if (!destroyed) {
1851 widget->Detach();
1852 widget->CloseNow();
1856 // Tests that killing a widget while animating it does not crash.
1857 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1858 scoped_ptr<Widget> widget(new Widget);
1859 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1860 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1861 params.bounds = gfx::Rect(50, 50, 250, 250);
1862 widget->Init(params);
1863 AnimationEndObserver animation_observer;
1864 WidgetBoundsObserver widget_observer;
1865 gfx::Rect bounds(0, 0, 50, 50);
1867 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1868 // animating the movement.
1869 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1870 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1871 ui::ScopedLayerAnimationSettings animation_settings(
1872 widget->GetLayer()->GetAnimator());
1873 animation_settings.AddObserver(&animation_observer);
1874 widget->AddObserver(&widget_observer);
1875 widget->Show();
1877 // Animate the bounds change.
1878 widget->SetBounds(bounds);
1879 widget.reset();
1880 EXPECT_FALSE(animation_observer.animation_completed());
1882 EXPECT_TRUE(animation_observer.animation_completed());
1883 EXPECT_EQ(widget_observer.bounds(), bounds);
1886 // A view that consumes mouse-pressed event and gesture-tap-down events.
1887 class RootViewTestView : public View {
1888 public:
1889 RootViewTestView(): View() {}
1891 private:
1892 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1893 return true;
1896 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1897 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1898 event->SetHandled();
1902 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1903 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1904 #if defined(OS_WIN)
1905 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1906 DISABLED_TestRootViewHandlersWhenHidden
1907 #else
1908 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1909 TestRootViewHandlersWhenHidden
1910 #endif
1911 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1912 Widget* widget = CreateTopLevelNativeWidget();
1913 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1914 View* view = new RootViewTestView();
1915 view->SetBounds(0, 0, 300, 300);
1916 internal::RootView* root_view =
1917 static_cast<internal::RootView*>(widget->GetRootView());
1918 root_view->AddChildView(view);
1920 // Check RootView::mouse_pressed_handler_.
1921 widget->Show();
1922 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1923 gfx::Point click_location(45, 15);
1924 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1925 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1926 widget->OnMouseEvent(&press);
1927 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1928 widget->Hide();
1929 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1931 // Check RootView::mouse_move_handler_.
1932 widget->Show();
1933 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1934 gfx::Point move_location(45, 15);
1935 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1936 widget->OnMouseEvent(&move);
1937 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1938 widget->Hide();
1939 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1941 // Check RootView::gesture_handler_.
1942 widget->Show();
1943 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1944 ui::GestureEvent tap_down(
1948 base::TimeDelta(),
1949 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0));
1950 widget->OnGestureEvent(&tap_down);
1951 EXPECT_EQ(view, GetGestureHandler(root_view));
1952 widget->Hide();
1953 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1955 widget->Close();
1958 // Convenience to make constructing a GestureEvent simpler.
1959 class GestureEventForTest : public ui::GestureEvent {
1960 public:
1961 GestureEventForTest(ui::EventType type, int x, int y)
1962 : GestureEvent(x,
1965 base::TimeDelta(),
1966 ui::GestureEventDetails(type, 0.0f, 0.0f)) {}
1968 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
1969 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
1972 // Tests that the |gesture_handler_| member in RootView is always NULL
1973 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
1974 // the release of the final touch point on the screen and that
1975 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
1976 // point are never dispatched to a view. Also verifies that
1977 // ui::ET_GESTURE_BEGIN is never dispatched to a view and does not change the
1978 // value of |gesture_handler_|.
1979 TEST_F(WidgetTest, GestureBeginAndEndEvents) {
1980 Widget* widget = CreateTopLevelNativeWidget();
1981 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1982 EventCountView* view = new EventCountView();
1983 view->SetBounds(0, 0, 300, 300);
1984 internal::RootView* root_view =
1985 static_cast<internal::RootView*>(widget->GetRootView());
1986 root_view->AddChildView(view);
1987 widget->Show();
1989 // If no gesture handler is set, dispatching a ui::ET_GESTURE_END or
1990 // ui::ET_GESTURE_BEGIN event should not set the gesture handler and
1991 // the events should remain unhandled because the handle mode of |view|
1992 // indicates that events should not be consumed.
1993 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1994 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
1995 widget->OnGestureEvent(&end);
1996 EXPECT_FALSE(end.handled());
1997 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1999 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 15, 15);
2000 widget->OnGestureEvent(&begin);
2001 EXPECT_FALSE(begin.handled());
2002 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2004 // Change the handle mode of |view| to indicate that it would like
2005 // to handle all events.
2006 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2008 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2009 // should not set the gesture handler and should not be marked as handled
2010 // because it is never dispatched.
2011 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2012 widget->OnGestureEvent(&begin);
2013 EXPECT_FALSE(begin.handled());
2014 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2016 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2017 // corresponding to a second touch point should not set the gesture handler
2018 // and should not be marked as handled because it is never dispatched.
2019 ui::GestureEventDetails details(ui::ET_GESTURE_END, 15, 15);
2020 details.set_touch_points(2);
2021 GestureEventForTest end_second_touch_point(details, 15, 15);
2022 widget->OnGestureEvent(&end_second_touch_point);
2023 EXPECT_FALSE(end_second_touch_point.handled());
2024 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2026 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_END
2027 // event corresponding to the final touch point should not set the gesture
2028 // handler, but it should be marked as handled because it was dispatched to
2029 // the view targeted by the event's location.
2030 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2031 widget->OnGestureEvent(&end);
2032 EXPECT_TRUE(end.handled());
2033 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2035 // If the gesture handler has been set by a previous gesture, then it should
2036 // remain unchanged on a ui::ET_GESTURE_BEGIN or a ui::ET_GESTURE_END
2037 // corresponding to a second touch point. It should be reset to NULL by a
2038 // ui::ET_GESTURE_END corresponding to the final touch point.
2039 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2040 widget->OnGestureEvent(&tap);
2041 EXPECT_TRUE(tap.handled());
2042 EXPECT_EQ(view, GetGestureHandler(root_view));
2044 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2045 widget->OnGestureEvent(&begin);
2046 EXPECT_FALSE(begin.handled());
2047 EXPECT_EQ(view, GetGestureHandler(root_view));
2049 end_second_touch_point = GestureEventForTest(details, 15, 15);
2050 widget->OnGestureEvent(&end_second_touch_point);
2051 EXPECT_FALSE(end_second_touch_point.handled());
2052 EXPECT_EQ(view, GetGestureHandler(root_view));
2054 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2055 widget->OnGestureEvent(&end);
2056 EXPECT_TRUE(end.handled());
2057 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2059 // If the gesture handler has been set by a previous gesture, then
2060 // it should remain unchanged on a ui::ET_GESTURE_BEGIN or a
2061 // ui::ET_GESTURE_END corresponding to a second touch point and be reset
2062 // to NULL by a ui::ET_GESTURE_END corresponding to the final touch point,
2063 // even when the gesture handler has indicated that it would not like to
2064 // handle any further events.
2065 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2066 widget->OnGestureEvent(&tap);
2067 EXPECT_TRUE(tap.handled());
2068 EXPECT_EQ(view, GetGestureHandler(root_view));
2070 // Change the handle mode of |view| to indicate that it does not want
2071 // to handle any further events.
2072 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2074 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2075 widget->OnGestureEvent(&begin);
2076 EXPECT_FALSE(begin.handled());
2077 EXPECT_EQ(view, GetGestureHandler(root_view));
2079 end_second_touch_point = GestureEventForTest(details, 15, 15);
2080 widget->OnGestureEvent(&end_second_touch_point);
2081 EXPECT_FALSE(end_second_touch_point.handled());
2082 EXPECT_EQ(view, GetGestureHandler(root_view));
2084 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2085 widget->OnGestureEvent(&end);
2086 EXPECT_FALSE(end.handled());
2087 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2089 widget->Close();
2092 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2093 // in a view hierarchy and that the default gesture handler in RootView is set
2094 // correctly.
2095 TEST_F(WidgetTest, GestureEventDispatch) {
2096 Widget* widget = CreateTopLevelNativeWidget();
2097 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2099 // Define a hierarchy of four views (coordinates are in
2100 // their parent coordinate space).
2101 // v1 (0, 0, 300, 300)
2102 // v2 (0, 0, 100, 100)
2103 // v3 (0, 0, 50, 50)
2104 // v4(0, 0, 10, 10)
2105 EventCountView* v1 = new EventCountView();
2106 v1->SetBounds(0, 0, 300, 300);
2107 EventCountView* v2 = new EventCountView();
2108 v2->SetBounds(0, 0, 100, 100);
2109 EventCountView* v3 = new EventCountView();
2110 v3->SetBounds(0, 0, 50, 50);
2111 EventCountView* v4 = new EventCountView();
2112 v4->SetBounds(0, 0, 10, 10);
2113 internal::RootView* root_view =
2114 static_cast<internal::RootView*>(widget->GetRootView());
2115 root_view->AddChildView(v1);
2116 v1->AddChildView(v2);
2117 v2->AddChildView(v3);
2118 v3->AddChildView(v4);
2120 widget->Show();
2122 // No gesture handler is set in the root view and none of the views in the
2123 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2124 // event should be dispatched to all views in the hierarchy, the gesture
2125 // handler should remain unset, and the event should remain unhandled.
2126 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2127 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2128 widget->OnGestureEvent(&tap);
2129 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2130 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2131 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2132 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2133 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2134 EXPECT_FALSE(tap.handled());
2136 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2137 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2138 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2139 // and the event should be marked as handled.
2140 v1->ResetCounts();
2141 v2->ResetCounts();
2142 v3->ResetCounts();
2143 v4->ResetCounts();
2144 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2145 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2146 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2147 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2148 widget->OnGestureEvent(&tap);
2149 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2150 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2151 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2152 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2153 EXPECT_EQ(v3, GetGestureHandler(root_view));
2154 EXPECT_TRUE(tap.handled());
2156 // The gesture handler is set to |v3| and all views handle all gesture event
2157 // types. In this case subsequent gesture events should only be dispatched to
2158 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2159 v1->ResetCounts();
2160 v2->ResetCounts();
2161 v3->ResetCounts();
2162 v4->ResetCounts();
2163 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2164 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2165 widget->OnGestureEvent(&tap);
2166 EXPECT_TRUE(tap.handled());
2167 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2168 widget->OnGestureEvent(&show_press);
2169 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2170 widget->OnGestureEvent(&tap);
2171 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2172 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2173 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2174 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2175 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2176 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2177 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2178 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2179 EXPECT_TRUE(tap.handled());
2180 EXPECT_TRUE(show_press.handled());
2181 EXPECT_EQ(v3, GetGestureHandler(root_view));
2183 // The gesture handler is set to |v3|, but |v3| does not handle
2184 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2185 // only to |v3|, but the event should remain unhandled. The gesture handler
2186 // should remain as |v3|.
2187 v1->ResetCounts();
2188 v2->ResetCounts();
2189 v3->ResetCounts();
2190 v4->ResetCounts();
2191 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2192 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2193 widget->OnGestureEvent(&tap);
2194 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2195 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2196 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2197 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2198 EXPECT_FALSE(tap.handled());
2199 EXPECT_EQ(v3, GetGestureHandler(root_view));
2201 widget->Close();
2204 // Tests that gesture scroll events will change the default gesture handler in
2205 // RootView if the current handler to which they are dispatched does not handle
2206 // gesture scroll events.
2207 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2208 Widget* widget = CreateTopLevelNativeWidget();
2209 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2211 // Define a hierarchy of four views (coordinates are in
2212 // their parent coordinate space).
2213 // v1 (0, 0, 300, 300)
2214 // v2 (0, 0, 100, 100)
2215 // v3 (0, 0, 50, 50)
2216 // v4(0, 0, 10, 10)
2217 EventCountView* v1 = new EventCountView();
2218 v1->SetBounds(0, 0, 300, 300);
2219 EventCountView* v2 = new EventCountView();
2220 v2->SetBounds(0, 0, 100, 100);
2221 EventCountView* v3 = new EventCountView();
2222 v3->SetBounds(0, 0, 50, 50);
2223 EventCountView* v4 = new EventCountView();
2224 v4->SetBounds(0, 0, 10, 10);
2225 internal::RootView* root_view =
2226 static_cast<internal::RootView*>(widget->GetRootView());
2227 root_view->AddChildView(v1);
2228 v1->AddChildView(v2);
2229 v2->AddChildView(v3);
2230 v3->AddChildView(v4);
2232 widget->Show();
2234 // Change the handle mode of |v3| to indicate that it would like to handle
2235 // gesture events.
2236 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2238 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2239 // should bubble up the views hierarchy until it reaches the first view
2240 // that will handle it (|v3|) and then sets the handler to |v3|.
2241 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2242 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2243 widget->OnGestureEvent(&tap_down);
2244 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2245 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2246 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2247 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2248 EXPECT_EQ(v3, GetGestureHandler(root_view));
2249 EXPECT_TRUE(tap_down.handled());
2250 v1->ResetCounts();
2251 v2->ResetCounts();
2252 v3->ResetCounts();
2253 v4->ResetCounts();
2255 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2256 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2257 widget->OnGestureEvent(&tap_cancel);
2258 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2259 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2260 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2261 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2262 EXPECT_EQ(v3, GetGestureHandler(root_view));
2263 EXPECT_TRUE(tap_cancel.handled());
2264 v1->ResetCounts();
2265 v2->ResetCounts();
2266 v3->ResetCounts();
2267 v4->ResetCounts();
2269 // Change the handle mode of |v3| to indicate that it would no longer like
2270 // to handle events, and change the mode of |v1| to indicate that it would
2271 // like to handle events.
2272 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2273 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2275 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2276 // handler (|v3|) does not handle scroll events, the event should bubble up
2277 // the views hierarchy until it reaches the first view that will handle
2278 // it (|v1|) and then sets the handler to |v1|.
2279 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2280 widget->OnGestureEvent(&scroll_begin);
2281 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2282 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2283 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2284 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2285 EXPECT_EQ(v1, GetGestureHandler(root_view));
2286 EXPECT_TRUE(scroll_begin.handled());
2287 v1->ResetCounts();
2288 v2->ResetCounts();
2289 v3->ResetCounts();
2290 v4->ResetCounts();
2292 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2293 // directly.
2294 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2295 widget->OnGestureEvent(&scroll_update);
2296 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2297 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2298 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2299 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2300 EXPECT_EQ(v1, GetGestureHandler(root_view));
2301 EXPECT_TRUE(scroll_update.handled());
2302 v1->ResetCounts();
2303 v2->ResetCounts();
2304 v3->ResetCounts();
2305 v4->ResetCounts();
2307 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2308 // directly and should not reset the gesture handler.
2309 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2310 widget->OnGestureEvent(&scroll_end);
2311 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2312 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2313 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2314 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2315 EXPECT_EQ(v1, GetGestureHandler(root_view));
2316 EXPECT_TRUE(scroll_end.handled());
2317 v1->ResetCounts();
2318 v2->ResetCounts();
2319 v3->ResetCounts();
2320 v4->ResetCounts();
2322 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2323 // still be dispatched to |v1| directly.
2324 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2325 widget->OnGestureEvent(&pinch_begin);
2326 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2327 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2328 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2329 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2330 EXPECT_EQ(v1, GetGestureHandler(root_view));
2331 EXPECT_TRUE(pinch_begin.handled());
2332 v1->ResetCounts();
2333 v2->ResetCounts();
2334 v3->ResetCounts();
2335 v4->ResetCounts();
2337 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2338 // set the gesture handler to NULL.
2339 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2340 widget->OnGestureEvent(&end);
2341 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2342 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2343 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2344 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2345 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2346 EXPECT_TRUE(end.handled());
2348 widget->Close();
2351 // Verifies that disabled views are permitted to be set as the default gesture
2352 // handler in RootView. Also verifies that gesture events targeted to a disabled
2353 // view are not actually dispatched to the view, but are still marked as
2354 // handled.
2355 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2356 Widget* widget = CreateTopLevelNativeWidget();
2357 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2359 // Define a hierarchy of four views (coordinates are in
2360 // their parent coordinate space).
2361 // v1 (0, 0, 300, 300)
2362 // v2 (0, 0, 100, 100)
2363 // v3 (0, 0, 50, 50)
2364 // v4(0, 0, 10, 10)
2365 EventCountView* v1 = new EventCountView();
2366 v1->SetBounds(0, 0, 300, 300);
2367 EventCountView* v2 = new EventCountView();
2368 v2->SetBounds(0, 0, 100, 100);
2369 EventCountView* v3 = new EventCountView();
2370 v3->SetBounds(0, 0, 50, 50);
2371 EventCountView* v4 = new EventCountView();
2372 v4->SetBounds(0, 0, 10, 10);
2373 internal::RootView* root_view =
2374 static_cast<internal::RootView*>(widget->GetRootView());
2375 root_view->AddChildView(v1);
2376 v1->AddChildView(v2);
2377 v2->AddChildView(v3);
2378 v3->AddChildView(v4);
2380 widget->Show();
2382 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2383 // disabled.
2384 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2385 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2386 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2387 v3->SetEnabled(false);
2389 // No gesture handler is set in the root view, so it should remain unset
2390 // after a GESTURE_END. The event is first dispatched to |v4| (which does
2391 // not want to handle the event) and is then targeted at |v3|. Since |v3|
2392 // is disabled, the event is not dispatched but is still marked as handled.
2393 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2394 widget->OnGestureEvent(&end);
2395 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2396 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2397 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2398 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_END));
2399 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2400 EXPECT_TRUE(end.handled());
2401 v1->ResetCounts();
2402 v2->ResetCounts();
2403 v3->ResetCounts();
2404 v4->ResetCounts();
2406 // No gesture handler is set in the root view. In this case the tap event
2407 // should be dispatched only to |v4|, the gesture handler should be set to
2408 // |v3|, and the event should be marked as handled.
2409 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2410 widget->OnGestureEvent(&tap);
2411 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2412 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2413 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2414 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2415 EXPECT_EQ(v3, GetGestureHandler(root_view));
2416 EXPECT_TRUE(tap.handled());
2417 v1->ResetCounts();
2418 v2->ResetCounts();
2419 v3->ResetCounts();
2420 v4->ResetCounts();
2422 // A subsequent gesture event should be marked as handled but not dispatched.
2423 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2424 widget->OnGestureEvent(&tap);
2425 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2426 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2427 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2428 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2429 EXPECT_EQ(v3, GetGestureHandler(root_view));
2430 EXPECT_TRUE(tap.handled());
2431 v1->ResetCounts();
2432 v2->ResetCounts();
2433 v3->ResetCounts();
2434 v4->ResetCounts();
2436 // A GESTURE_END should reset the default gesture handler to NULL. It should
2437 // also not be dispatched to |v3| but still marked as handled.
2438 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2439 widget->OnGestureEvent(&end);
2440 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2441 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2442 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2443 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2444 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2445 EXPECT_TRUE(end.handled());
2446 v1->ResetCounts();
2447 v2->ResetCounts();
2448 v3->ResetCounts();
2449 v4->ResetCounts();
2451 // Change the handle mode of |v3| to indicate that it would no longer like
2452 // to handle events which are dispatched to it.
2453 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2455 // No gesture handler is set in the root view. In this case the tap event
2456 // should be dispatched only to |v4| and the event should be marked as
2457 // handled. Furthermore, the gesture handler should be set to
2458 // |v3|; even though |v3| does not explicitly handle events, it is a
2459 // valid target for the tap event because it is disabled.
2460 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2461 widget->OnGestureEvent(&tap);
2462 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2463 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2464 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2465 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2466 EXPECT_EQ(v3, GetGestureHandler(root_view));
2467 EXPECT_TRUE(tap.handled());
2468 v1->ResetCounts();
2469 v2->ResetCounts();
2470 v3->ResetCounts();
2471 v4->ResetCounts();
2473 // A GESTURE_END should reset the default gesture handler to NULL. It should
2474 // also not be dispatched to |v3| but still marked as handled.
2475 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2476 widget->OnGestureEvent(&end);
2477 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2478 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2479 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2480 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2481 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2482 EXPECT_TRUE(end.handled());
2484 widget->Close();
2487 // Test the result of Widget::GetAllChildWidgets().
2488 TEST_F(WidgetTest, GetAllChildWidgets) {
2489 // Create the following widget hierarchy:
2491 // toplevel
2492 // +-- w1
2493 // +-- w11
2494 // +-- w2
2495 // +-- w21
2496 // +-- w22
2497 Widget* toplevel = CreateTopLevelPlatformWidget();
2498 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2499 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2500 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2501 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2502 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2504 std::set<Widget*> expected;
2505 expected.insert(toplevel);
2506 expected.insert(w1);
2507 expected.insert(w11);
2508 expected.insert(w2);
2509 expected.insert(w21);
2510 expected.insert(w22);
2512 std::set<Widget*> widgets;
2513 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2515 EXPECT_EQ(expected.size(), widgets.size());
2516 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2519 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2520 // a vector.
2521 class DestroyedTrackingView : public View {
2522 public:
2523 DestroyedTrackingView(const std::string& name,
2524 std::vector<std::string>* add_to)
2525 : name_(name),
2526 add_to_(add_to) {
2529 virtual ~DestroyedTrackingView() {
2530 add_to_->push_back(name_);
2533 private:
2534 const std::string name_;
2535 std::vector<std::string>* add_to_;
2537 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2540 class WidgetChildDestructionTest : public WidgetTest {
2541 public:
2542 WidgetChildDestructionTest() {}
2544 // Creates a top level and a child, destroys the child and verifies the views
2545 // of the child are destroyed before the views of the parent.
2546 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2547 bool child_has_desktop_native_widget_aura) {
2548 // When a View is destroyed its name is added here.
2549 std::vector<std::string> destroyed;
2551 Widget* top_level = new Widget;
2552 Widget::InitParams params =
2553 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2554 #if !defined(OS_CHROMEOS)
2555 if (top_level_has_desktop_native_widget_aura)
2556 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2557 #endif
2558 top_level->Init(params);
2559 top_level->GetRootView()->AddChildView(
2560 new DestroyedTrackingView("parent", &destroyed));
2561 top_level->Show();
2563 Widget* child = new Widget;
2564 Widget::InitParams child_params =
2565 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2566 child_params.parent = top_level->GetNativeView();
2567 #if !defined(OS_CHROMEOS)
2568 if (child_has_desktop_native_widget_aura)
2569 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2570 #endif
2571 child->Init(child_params);
2572 child->GetRootView()->AddChildView(
2573 new DestroyedTrackingView("child", &destroyed));
2574 child->Show();
2576 // Should trigger destruction of the child too.
2577 top_level->native_widget_private()->CloseNow();
2579 // Child should be destroyed first.
2580 ASSERT_EQ(2u, destroyed.size());
2581 EXPECT_EQ("child", destroyed[0]);
2582 EXPECT_EQ("parent", destroyed[1]);
2585 private:
2586 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2589 #if !defined(OS_CHROMEOS)
2590 // See description of RunDestroyChildWidgetsTest(). Parent uses
2591 // DesktopNativeWidgetAura.
2592 TEST_F(WidgetChildDestructionTest,
2593 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2594 RunDestroyChildWidgetsTest(true, false);
2597 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2598 // DesktopNativeWidgetAura.
2599 TEST_F(WidgetChildDestructionTest,
2600 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2601 RunDestroyChildWidgetsTest(true, true);
2603 #endif // !defined(OS_CHROMEOS)
2605 // See description of RunDestroyChildWidgetsTest().
2606 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2607 RunDestroyChildWidgetsTest(false, false);
2610 #if !defined(OS_CHROMEOS)
2611 // Provides functionality to create a window modal dialog.
2612 class ModalDialogDelegate : public DialogDelegateView {
2613 public:
2614 ModalDialogDelegate() {}
2615 virtual ~ModalDialogDelegate() {}
2617 // WidgetDelegate overrides.
2618 virtual ui::ModalType GetModalType() const OVERRIDE {
2619 return ui::MODAL_TYPE_WINDOW;
2622 private:
2623 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2626 // This test verifies that whether mouse events when a modal dialog is
2627 // displayed are eaten or recieved by the dialog.
2628 TEST_F(WidgetTest, WindowMouseModalityTest) {
2629 // Create a top level widget.
2630 Widget top_level_widget;
2631 Widget::InitParams init_params =
2632 CreateParams(Widget::InitParams::TYPE_WINDOW);
2633 init_params.show_state = ui::SHOW_STATE_NORMAL;
2634 gfx::Rect initial_bounds(0, 0, 500, 500);
2635 init_params.bounds = initial_bounds;
2636 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2637 init_params.native_widget =
2638 new PlatformDesktopNativeWidget(&top_level_widget);
2639 top_level_widget.Init(init_params);
2640 top_level_widget.Show();
2641 EXPECT_TRUE(top_level_widget.IsVisible());
2643 // Create a view and validate that a mouse moves makes it to the view.
2644 EventCountView* widget_view = new EventCountView();
2645 widget_view->SetBounds(0, 0, 10, 10);
2646 top_level_widget.GetRootView()->AddChildView(widget_view);
2648 gfx::Point cursor_location_main(5, 5);
2649 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2650 cursor_location_main,
2651 cursor_location_main,
2652 ui::EF_NONE,
2653 ui::EF_NONE);
2654 ui::EventDispatchDetails details =
2655 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2656 ASSERT_FALSE(details.dispatcher_destroyed);
2658 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2659 widget_view->ResetCounts();
2661 // Create a modal dialog and validate that a mouse down message makes it to
2662 // the main view within the dialog.
2664 // This instance will be destroyed when the dialog is destroyed.
2665 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2667 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2668 dialog_delegate, NULL, top_level_widget.GetNativeView());
2669 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2670 EventCountView* dialog_widget_view = new EventCountView();
2671 dialog_widget_view->SetBounds(0, 0, 50, 50);
2672 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2673 modal_dialog_widget->Show();
2674 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2676 gfx::Point cursor_location_dialog(100, 100);
2677 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2678 cursor_location_dialog,
2679 cursor_location_dialog,
2680 ui::EF_NONE,
2681 ui::EF_NONE);
2682 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2683 &mouse_down_dialog);
2684 ASSERT_FALSE(details.dispatcher_destroyed);
2685 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2687 // Send a mouse move message to the main window. It should not be received by
2688 // the main window as the modal dialog is still active.
2689 gfx::Point cursor_location_main2(6, 6);
2690 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2691 cursor_location_main2,
2692 cursor_location_main2,
2693 ui::EF_NONE,
2694 ui::EF_NONE);
2695 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2696 &mouse_down_main);
2697 ASSERT_FALSE(details.dispatcher_destroyed);
2698 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2700 modal_dialog_widget->CloseNow();
2701 top_level_widget.CloseNow();
2704 // Verifies nativeview visbility matches that of Widget visibility when
2705 // SetFullscreen is invoked.
2706 TEST_F(WidgetTest, FullscreenStatePropagated) {
2707 Widget::InitParams init_params =
2708 CreateParams(Widget::InitParams::TYPE_WINDOW);
2709 init_params.show_state = ui::SHOW_STATE_NORMAL;
2710 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2711 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2714 Widget top_level_widget;
2715 top_level_widget.Init(init_params);
2716 top_level_widget.SetFullscreen(true);
2717 EXPECT_EQ(top_level_widget.IsVisible(),
2718 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2719 top_level_widget.CloseNow();
2721 #if !defined(OS_CHROMEOS)
2723 Widget top_level_widget;
2724 init_params.native_widget =
2725 new PlatformDesktopNativeWidget(&top_level_widget);
2726 top_level_widget.Init(init_params);
2727 top_level_widget.SetFullscreen(true);
2728 EXPECT_EQ(top_level_widget.IsVisible(),
2729 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2730 top_level_widget.CloseNow();
2732 #endif
2734 #if defined(OS_WIN)
2736 // Provides functionality to test widget activation via an activation flag
2737 // which can be set by an accessor.
2738 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2739 public:
2740 ModalWindowTestWidgetDelegate()
2741 : widget_(NULL),
2742 can_activate_(true) {}
2744 virtual ~ModalWindowTestWidgetDelegate() {}
2746 // Overridden from WidgetDelegate:
2747 virtual void DeleteDelegate() OVERRIDE {
2748 delete this;
2750 virtual Widget* GetWidget() OVERRIDE {
2751 return widget_;
2753 virtual const Widget* GetWidget() const OVERRIDE {
2754 return widget_;
2756 virtual bool CanActivate() const OVERRIDE {
2757 return can_activate_;
2759 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2760 return true;
2763 void set_can_activate(bool can_activate) {
2764 can_activate_ = can_activate;
2767 void set_widget(Widget* widget) {
2768 widget_ = widget;
2771 private:
2772 Widget* widget_;
2773 bool can_activate_;
2775 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2778 // Tests whether we can activate the top level widget when a modal dialog is
2779 // active.
2780 TEST_F(WidgetTest, WindowModalityActivationTest) {
2781 // Destroyed when the top level widget created below is destroyed.
2782 ModalWindowTestWidgetDelegate* widget_delegate =
2783 new ModalWindowTestWidgetDelegate;
2784 // Create a top level widget.
2785 Widget top_level_widget;
2786 Widget::InitParams init_params =
2787 CreateParams(Widget::InitParams::TYPE_WINDOW);
2788 init_params.show_state = ui::SHOW_STATE_NORMAL;
2789 gfx::Rect initial_bounds(0, 0, 500, 500);
2790 init_params.bounds = initial_bounds;
2791 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2792 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2793 init_params.delegate = widget_delegate;
2794 top_level_widget.Init(init_params);
2795 widget_delegate->set_widget(&top_level_widget);
2796 top_level_widget.Show();
2797 EXPECT_TRUE(top_level_widget.IsVisible());
2799 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2800 EXPECT_TRUE(::IsWindow(win32_window));
2802 // This instance will be destroyed when the dialog is destroyed.
2803 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2805 // We should be able to activate the window even if the WidgetDelegate
2806 // says no, when a modal dialog is active.
2807 widget_delegate->set_can_activate(false);
2809 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2810 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2811 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2812 modal_dialog_widget->Show();
2813 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2815 LRESULT activate_result = ::SendMessage(
2816 win32_window,
2817 WM_MOUSEACTIVATE,
2818 reinterpret_cast<WPARAM>(win32_window),
2819 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2820 EXPECT_EQ(activate_result, MA_ACTIVATE);
2822 modal_dialog_widget->CloseNow();
2823 top_level_widget.CloseNow();
2825 #endif // defined(OS_WIN)
2826 #endif // !defined(OS_CHROMEOS)
2828 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2829 Widget* widget = CreateTopLevelPlatformWidget();
2831 widget->Show();
2832 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2834 widget->CloseNow();
2837 // OSX does not have a per-application "active" window such as provided by
2838 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
2839 // is updated asynchronously.
2840 #if defined(OS_MACOSX)
2841 #define MAYBE_ShowInactive DISABLED_ShowInactive
2842 #else
2843 #define MAYBE_ShowInactive ShowInactive
2844 #endif
2845 TEST_F(WidgetTest, MAYBE_ShowInactive) {
2846 Widget* widget = CreateTopLevelPlatformWidget();
2848 widget->ShowInactive();
2849 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2851 widget->CloseNow();
2854 TEST_F(WidgetTest, InactiveBeforeShow) {
2855 Widget* widget = CreateTopLevelPlatformWidget();
2857 EXPECT_FALSE(widget->IsActive());
2858 EXPECT_FALSE(widget->IsVisible());
2860 widget->Show();
2862 EXPECT_TRUE(widget->IsActive());
2863 EXPECT_TRUE(widget->IsVisible());
2865 widget->CloseNow();
2868 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2869 // Create 2 widgets to ensure window layering does not change.
2870 Widget* widget = CreateTopLevelPlatformWidget();
2871 Widget* widget2 = CreateTopLevelPlatformWidget();
2873 widget2->Show();
2874 EXPECT_FALSE(widget->IsActive());
2875 EXPECT_TRUE(widget2->IsVisible());
2876 EXPECT_TRUE(widget2->IsActive());
2878 widget->Show();
2879 EXPECT_TRUE(widget->IsActive());
2880 EXPECT_FALSE(widget2->IsActive());
2881 widget->ShowInactive();
2882 EXPECT_TRUE(widget->IsActive());
2883 EXPECT_FALSE(widget2->IsActive());
2884 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2886 widget2->CloseNow();
2887 widget->CloseNow();
2890 TEST_F(WidgetTest, ShowAfterShowInactive) {
2891 Widget* widget = CreateTopLevelPlatformWidget();
2893 widget->ShowInactive();
2894 widget->Show();
2895 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2897 widget->CloseNow();
2900 #if !defined(OS_CHROMEOS)
2901 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
2902 Widget* widget = CreateTopLevelPlatformWidget();
2903 widget->Show();
2904 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2906 Widget widget2;
2907 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2908 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
2909 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2910 widget2.Init(params);
2911 widget2.Show();
2913 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
2914 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2916 widget->CloseNow();
2917 widget2.CloseNow();
2919 #endif // !defined(OS_CHROMEOS)
2921 namespace {
2923 class FullscreenAwareFrame : public views::NonClientFrameView {
2924 public:
2925 explicit FullscreenAwareFrame(views::Widget* widget)
2926 : widget_(widget), fullscreen_layout_called_(false) {}
2927 virtual ~FullscreenAwareFrame() {}
2929 // views::NonClientFrameView overrides:
2930 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
2931 return gfx::Rect();
2933 virtual gfx::Rect GetWindowBoundsForClientBounds(
2934 const gfx::Rect& client_bounds) const OVERRIDE {
2935 return gfx::Rect();
2937 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
2938 return HTNOWHERE;
2940 virtual void GetWindowMask(const gfx::Size& size,
2941 gfx::Path* window_mask) OVERRIDE {}
2942 virtual void ResetWindowControls() OVERRIDE {}
2943 virtual void UpdateWindowIcon() OVERRIDE {}
2944 virtual void UpdateWindowTitle() OVERRIDE {}
2946 // views::View overrides:
2947 virtual void Layout() OVERRIDE {
2948 if (widget_->IsFullscreen())
2949 fullscreen_layout_called_ = true;
2952 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
2954 private:
2955 views::Widget* widget_;
2956 bool fullscreen_layout_called_;
2958 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
2961 } // namespace
2963 // Tests that frame Layout is called when a widget goes fullscreen without
2964 // changing its size or title.
2965 TEST_F(WidgetTest, FullscreenFrameLayout) {
2966 Widget* widget = CreateTopLevelPlatformWidget();
2967 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
2968 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
2970 widget->Maximize();
2971 RunPendingMessages();
2973 EXPECT_FALSE(frame->fullscreen_layout_called());
2974 widget->SetFullscreen(true);
2975 widget->Show();
2976 RunPendingMessages();
2977 EXPECT_TRUE(frame->fullscreen_layout_called());
2979 widget->CloseNow();
2982 #if !defined(OS_CHROMEOS)
2983 namespace {
2985 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
2986 // OnWindowDestroying.
2987 class IsActiveFromDestroyObserver : public WidgetObserver {
2988 public:
2989 IsActiveFromDestroyObserver() {}
2990 virtual ~IsActiveFromDestroyObserver() {}
2991 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
2992 widget->IsActive();
2995 private:
2996 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
2999 } // namespace
3001 // Verifies Widget::IsActive() invoked from
3002 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3003 TEST_F(WidgetTest, IsActiveFromDestroy) {
3004 // Create two widgets, one a child of the other.
3005 IsActiveFromDestroyObserver observer;
3006 Widget parent_widget;
3007 Widget::InitParams parent_params =
3008 CreateParams(Widget::InitParams::TYPE_POPUP);
3009 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3010 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3011 parent_widget.Init(parent_params);
3012 parent_widget.Show();
3014 Widget child_widget;
3015 Widget::InitParams child_params =
3016 CreateParams(Widget::InitParams::TYPE_POPUP);
3017 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3018 child_params.context = parent_widget.GetNativeWindow();
3019 child_widget.Init(child_params);
3020 child_widget.AddObserver(&observer);
3021 child_widget.Show();
3023 parent_widget.CloseNow();
3025 #endif // !defined(OS_CHROMEOS)
3027 // Tests that events propagate through from the dispatcher with the correct
3028 // event type, and that the different platforms behave the same.
3029 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3030 EventCountView* view = new EventCountView;
3031 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3032 view->SetBounds(10, 10, 50, 40);
3034 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3035 widget->GetRootView()->AddChildView(view);
3037 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3038 widget->Show();
3040 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3041 generator.set_current_location(gfx::Point(20, 20));
3043 generator.ClickLeftButton();
3044 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3045 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3046 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3048 generator.PressRightButton();
3049 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3050 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3051 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3053 generator.ReleaseRightButton();
3054 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3055 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3056 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3058 // Test mouse move events.
3059 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3060 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3062 // Move the mouse within the view (20, 20) -> (30, 30).
3063 generator.MoveMouseTo(gfx::Point(30, 30));
3064 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3065 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3066 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3068 // Move it again - entered count shouldn't change.
3069 generator.MoveMouseTo(gfx::Point(31, 31));
3070 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3071 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3072 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3074 // Move it off the view.
3075 generator.MoveMouseTo(gfx::Point(5, 5));
3076 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3077 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3078 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3080 // Move it back on.
3081 generator.MoveMouseTo(gfx::Point(20, 20));
3082 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3083 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3084 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3086 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3087 generator.DragMouseTo(gfx::Point(40, 40));
3088 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3089 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3090 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3091 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3093 widget->CloseNow();
3096 } // namespace test
3097 } // namespace views