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.
4
5 #include <algorithm>
6 #include <set>
7
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"
34
35 #if defined(OS_WIN)
36 #include "ui/views/win/hwnd_util.h"
37 #endif
38
39 namespace views {
40 namespace test {
41
42 namespace {
43
44 // TODO(tdanderson): This utility function is used in different unittest
45 // files. Move to a common location to avoid
46 // repeated code.
ConvertPointFromWidgetToView(View * view,const gfx::Point & p)47 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
48 gfx::Point tmp(p);
49 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
50 return tmp;
51 }
52
53 } // namespace
54
55 // A view that keeps track of the events it receives, optionally consuming them.
56 class EventCountView : public View {
57 public:
58 // Whether to call SetHandled() on events as they are received. For some event
59 // types, this will allow EventCountView to receives future events in the
60 // event sequence, such as a drag.
61 enum HandleMode {
62 PROPAGATE_EVENTS,
63 CONSUME_EVENTS
64 };
65
EventCountView()66 EventCountView()
67 : last_flags_(0),
68 handle_mode_(PROPAGATE_EVENTS) {}
69
~EventCountView()70 virtual ~EventCountView() {}
71
GetEventCount(ui::EventType type)72 int GetEventCount(ui::EventType type) {
73 return event_count_[type];
74 }
75
ResetCounts()76 void ResetCounts() {
77 event_count_.clear();
78 }
79
last_flags() const80 int last_flags() const {
81 return last_flags_;
82 }
83
set_handle_mode(HandleMode handle_mode)84 void set_handle_mode(HandleMode handle_mode) {
85 handle_mode_ = handle_mode;
86 }
87
88 protected:
89 // Overridden from View:
OnMouseMoved(const ui::MouseEvent & event)90 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
91 // MouseMove events are not re-dispatched from the RootView.
92 ++event_count_[ui::ET_MOUSE_MOVED];
93 last_flags_ = 0;
94 }
95
96 // Overridden from ui::EventHandler:
OnKeyEvent(ui::KeyEvent * event)97 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
98 RecordEvent(event);
99 }
OnMouseEvent(ui::MouseEvent * event)100 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
101 RecordEvent(event);
102 }
OnScrollEvent(ui::ScrollEvent * event)103 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
104 RecordEvent(event);
105 }
OnGestureEvent(ui::GestureEvent * event)106 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
107 RecordEvent(event);
108 }
109
110 private:
RecordEvent(ui::Event * event)111 void RecordEvent(ui::Event* event) {
112 ++event_count_[event->type()];
113 last_flags_ = event->flags();
114 if (handle_mode_ == CONSUME_EVENTS)
115 event->SetHandled();
116 }
117
118 std::map<ui::EventType, int> event_count_;
119 int last_flags_;
120 HandleMode handle_mode_;
121
122 DISALLOW_COPY_AND_ASSIGN(EventCountView);
123 };
124
125 // A view that keeps track of the events it receives, and consumes all scroll
126 // gesture events and ui::ET_SCROLL events.
127 class ScrollableEventCountView : public EventCountView {
128 public:
ScrollableEventCountView()129 ScrollableEventCountView() {}
~ScrollableEventCountView()130 virtual ~ScrollableEventCountView() {}
131
132 private:
133 // Overridden from ui::EventHandler:
OnGestureEvent(ui::GestureEvent * event)134 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
135 EventCountView::OnGestureEvent(event);
136 switch (event->type()) {
137 case ui::ET_GESTURE_SCROLL_BEGIN:
138 case ui::ET_GESTURE_SCROLL_UPDATE:
139 case ui::ET_GESTURE_SCROLL_END:
140 case ui::ET_SCROLL_FLING_START:
141 event->SetHandled();
142 break;
143 default:
144 break;
145 }
146 }
147
OnScrollEvent(ui::ScrollEvent * event)148 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
149 EventCountView::OnScrollEvent(event);
150 if (event->type() == ui::ET_SCROLL)
151 event->SetHandled();
152 }
153
154 DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
155 };
156
157 // A view that implements GetMinimumSize.
158 class MinimumSizeFrameView : public NativeFrameView {
159 public:
MinimumSizeFrameView(Widget * frame)160 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
~MinimumSizeFrameView()161 virtual ~MinimumSizeFrameView() {}
162
163 private:
164 // Overridden from View:
GetMinimumSize() const165 virtual gfx::Size GetMinimumSize() const OVERRIDE {
166 return gfx::Size(300, 400);
167 }
168
169 DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
170 };
171
172 // An event handler that simply keeps a count of the different types of events
173 // it receives.
174 class EventCountHandler : public ui::EventHandler {
175 public:
EventCountHandler()176 EventCountHandler() {}
~EventCountHandler()177 virtual ~EventCountHandler() {}
178
GetEventCount(ui::EventType type)179 int GetEventCount(ui::EventType type) {
180 return event_count_[type];
181 }
182
ResetCounts()183 void ResetCounts() {
184 event_count_.clear();
185 }
186
187 protected:
188 // Overridden from ui::EventHandler:
OnEvent(ui::Event * event)189 virtual void OnEvent(ui::Event* event) OVERRIDE {
190 RecordEvent(*event);
191 ui::EventHandler::OnEvent(event);
192 }
193
194 private:
RecordEvent(const ui::Event & event)195 void RecordEvent(const ui::Event& event) {
196 ++event_count_[event.type()];
197 }
198
199 std::map<ui::EventType, int> event_count_;
200
201 DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
202 };
203
204 // Class that closes the widget (which ends up deleting it immediately) when the
205 // appropriate event is received.
206 class CloseWidgetView : public View {
207 public:
CloseWidgetView(ui::EventType event_type)208 explicit CloseWidgetView(ui::EventType event_type)
209 : event_type_(event_type) {
210 }
211
212 // ui::EventHandler override:
OnEvent(ui::Event * event)213 virtual void OnEvent(ui::Event* event) OVERRIDE {
214 if (event->type() == event_type_) {
215 // Go through NativeWidgetPrivate to simulate what happens if the OS
216 // deletes the NativeWindow out from under us.
217 GetWidget()->native_widget_private()->CloseNow();
218 } else {
219 View::OnEvent(event);
220 if (!event->IsTouchEvent())
221 event->SetHandled();
222 }
223 }
224
225 private:
226 const ui::EventType event_type_;
227
228 DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
229 };
230
GetWidgetShowState(const Widget * widget)231 ui::WindowShowState GetWidgetShowState(const Widget* widget) {
232 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
233 // because the former is implemented on all platforms but the latter is not.
234 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
235 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
236 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
237 widget->IsActive() ? ui::SHOW_STATE_NORMAL :
238 ui::SHOW_STATE_INACTIVE;
239 }
240
TEST_F(WidgetTest,WidgetInitParams)241 TEST_F(WidgetTest, WidgetInitParams) {
242 // Widgets are not transparent by default.
243 Widget::InitParams init1;
244 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
245 }
246
247 ////////////////////////////////////////////////////////////////////////////////
248 // Widget::GetTopLevelWidget tests.
249
TEST_F(WidgetTest,GetTopLevelWidget_Native)250 TEST_F(WidgetTest, GetTopLevelWidget_Native) {
251 // Create a hierarchy of native widgets.
252 Widget* toplevel = CreateTopLevelPlatformWidget();
253 gfx::NativeView parent = toplevel->GetNativeView();
254 Widget* child = CreateChildPlatformWidget(parent);
255
256 EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
257 EXPECT_EQ(toplevel, child->GetTopLevelWidget());
258
259 toplevel->CloseNow();
260 // |child| should be automatically destroyed with |toplevel|.
261 }
262
263 // Test if a focus manager and an inputmethod work without CHECK failure
264 // when window activation changes.
TEST_F(WidgetTest,ChangeActivation)265 TEST_F(WidgetTest, ChangeActivation) {
266 Widget* top1 = CreateTopLevelPlatformWidget();
267 // CreateInputMethod before activated
268 top1->GetInputMethod();
269 top1->Show();
270 RunPendingMessages();
271
272 Widget* top2 = CreateTopLevelPlatformWidget();
273 top2->Show();
274 RunPendingMessages();
275
276 top1->Activate();
277 RunPendingMessages();
278
279 // Create InputMethod after deactivated.
280 top2->GetInputMethod();
281 top2->Activate();
282 RunPendingMessages();
283
284 top1->Activate();
285 RunPendingMessages();
286
287 top1->CloseNow();
288 top2->CloseNow();
289 }
290
291 // Tests visibility of child widgets.
TEST_F(WidgetTest,Visibility)292 TEST_F(WidgetTest, Visibility) {
293 Widget* toplevel = CreateTopLevelPlatformWidget();
294 gfx::NativeView parent = toplevel->GetNativeView();
295 Widget* child = CreateChildPlatformWidget(parent);
296
297 EXPECT_FALSE(toplevel->IsVisible());
298 EXPECT_FALSE(child->IsVisible());
299
300 child->Show();
301
302 EXPECT_FALSE(toplevel->IsVisible());
303 EXPECT_FALSE(child->IsVisible());
304
305 toplevel->Show();
306
307 EXPECT_TRUE(toplevel->IsVisible());
308 EXPECT_TRUE(child->IsVisible());
309
310 toplevel->CloseNow();
311 // |child| should be automatically destroyed with |toplevel|.
312 }
313
314 ////////////////////////////////////////////////////////////////////////////////
315 // Widget ownership tests.
316 //
317 // Tests various permutations of Widget ownership specified in the
318 // InitParams::Ownership param.
319
320 // A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
321 class WidgetOwnershipTest : public WidgetTest {
322 public:
WidgetOwnershipTest()323 WidgetOwnershipTest() {}
~WidgetOwnershipTest()324 virtual ~WidgetOwnershipTest() {}
325
SetUp()326 virtual void SetUp() {
327 WidgetTest::SetUp();
328 desktop_widget_ = CreateTopLevelPlatformWidget();
329 }
330
TearDown()331 virtual void TearDown() {
332 desktop_widget_->CloseNow();
333 WidgetTest::TearDown();
334 }
335
336 private:
337 Widget* desktop_widget_;
338
339 DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
340 };
341
342 // A bag of state to monitor destructions.
343 struct OwnershipTestState {
OwnershipTestStateviews::test::OwnershipTestState344 OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
345
346 bool widget_deleted;
347 bool native_widget_deleted;
348 };
349
350 // A platform NativeWidget subclass that updates a bag of state when it is
351 // destroyed.
352 class OwnershipTestNativeWidget : public PlatformNativeWidget {
353 public:
OwnershipTestNativeWidget(internal::NativeWidgetDelegate * delegate,OwnershipTestState * state)354 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
355 OwnershipTestState* state)
356 : PlatformNativeWidget(delegate),
357 state_(state) {
358 }
~OwnershipTestNativeWidget()359 virtual ~OwnershipTestNativeWidget() {
360 state_->native_widget_deleted = true;
361 }
362
363 private:
364 OwnershipTestState* state_;
365
366 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
367 };
368
369 // A views NativeWidget subclass that updates a bag of state when it is
370 // destroyed.
371 class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
372 public:
OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate * delegate,OwnershipTestState * state)373 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
374 OwnershipTestState* state)
375 : NativeWidgetCapture(delegate),
376 state_(state) {
377 }
~OwnershipTestNativeWidgetAura()378 virtual ~OwnershipTestNativeWidgetAura() {
379 state_->native_widget_deleted = true;
380 }
381
382 private:
383 OwnershipTestState* state_;
384
385 DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
386 };
387
388 // A Widget subclass that updates a bag of state when it is destroyed.
389 class OwnershipTestWidget : public Widget {
390 public:
OwnershipTestWidget(OwnershipTestState * state)391 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
~OwnershipTestWidget()392 virtual ~OwnershipTestWidget() {
393 state_->widget_deleted = true;
394 }
395
396 private:
397 OwnershipTestState* state_;
398
399 DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
400 };
401
402 // Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
403 // widget.
TEST_F(WidgetOwnershipTest,Ownership_WidgetOwnsPlatformNativeWidget)404 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
405 OwnershipTestState state;
406
407 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
408 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
409 params.native_widget =
410 new OwnershipTestNativeWidgetAura(widget.get(), &state);
411 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
412 widget->Init(params);
413
414 // Now delete the Widget, which should delete the NativeWidget.
415 widget.reset();
416
417 EXPECT_TRUE(state.widget_deleted);
418 EXPECT_TRUE(state.native_widget_deleted);
419
420 // TODO(beng): write test for this ownership scenario and the NativeWidget
421 // being deleted out from under the Widget.
422 }
423
424 // Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
TEST_F(WidgetOwnershipTest,Ownership_WidgetOwnsViewsNativeWidget)425 TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
426 OwnershipTestState state;
427
428 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
429 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
430 params.native_widget =
431 new OwnershipTestNativeWidgetAura(widget.get(), &state);
432 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
433 widget->Init(params);
434
435 // Now delete the Widget, which should delete the NativeWidget.
436 widget.reset();
437
438 EXPECT_TRUE(state.widget_deleted);
439 EXPECT_TRUE(state.native_widget_deleted);
440
441 // TODO(beng): write test for this ownership scenario and the NativeWidget
442 // being deleted out from under the Widget.
443 }
444
445 // Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
446 // destroy the parent view.
TEST_F(WidgetOwnershipTest,Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView)447 TEST_F(WidgetOwnershipTest,
448 Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
449 OwnershipTestState state;
450
451 Widget* toplevel = CreateTopLevelPlatformWidget();
452
453 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
454 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
455 params.native_widget =
456 new OwnershipTestNativeWidgetAura(widget.get(), &state);
457 params.parent = toplevel->GetNativeView();
458 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
459 widget->Init(params);
460
461 // Now close the toplevel, which deletes the view hierarchy.
462 toplevel->CloseNow();
463
464 RunPendingMessages();
465
466 // This shouldn't delete the widget because it shouldn't be deleted
467 // from the native side.
468 EXPECT_FALSE(state.widget_deleted);
469 EXPECT_FALSE(state.native_widget_deleted);
470
471 // Now delete it explicitly.
472 widget.reset();
473
474 EXPECT_TRUE(state.widget_deleted);
475 EXPECT_TRUE(state.native_widget_deleted);
476 }
477
478 // NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
479 // widget.
TEST_F(WidgetOwnershipTest,Ownership_PlatformNativeWidgetOwnsWidget)480 TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
481 OwnershipTestState state;
482
483 Widget* widget = new OwnershipTestWidget(&state);
484 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
485 params.native_widget =
486 new OwnershipTestNativeWidgetAura(widget, &state);
487 widget->Init(params);
488
489 // Now destroy the native widget.
490 widget->CloseNow();
491
492 EXPECT_TRUE(state.widget_deleted);
493 EXPECT_TRUE(state.native_widget_deleted);
494 }
495
496 // NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
TEST_F(WidgetOwnershipTest,Ownership_ViewsNativeWidgetOwnsWidget)497 TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
498 OwnershipTestState state;
499
500 Widget* toplevel = CreateTopLevelPlatformWidget();
501
502 Widget* widget = new OwnershipTestWidget(&state);
503 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
504 params.native_widget =
505 new OwnershipTestNativeWidgetAura(widget, &state);
506 params.parent = toplevel->GetNativeView();
507 widget->Init(params);
508
509 // Now destroy the native widget. This is achieved by closing the toplevel.
510 toplevel->CloseNow();
511
512 // The NativeWidget won't be deleted until after a return to the message loop
513 // so we have to run pending messages before testing the destruction status.
514 RunPendingMessages();
515
516 EXPECT_TRUE(state.widget_deleted);
517 EXPECT_TRUE(state.native_widget_deleted);
518 }
519
520 // NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
521 // widget, destroyed out from under it by the OS.
TEST_F(WidgetOwnershipTest,Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy)522 TEST_F(WidgetOwnershipTest,
523 Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
524 OwnershipTestState state;
525
526 Widget* widget = new OwnershipTestWidget(&state);
527 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
528 params.native_widget =
529 new OwnershipTestNativeWidgetAura(widget, &state);
530 widget->Init(params);
531
532 // Now simulate a destroy of the platform native widget from the OS:
533 SimulateNativeDestroy(widget);
534
535 EXPECT_TRUE(state.widget_deleted);
536 EXPECT_TRUE(state.native_widget_deleted);
537 }
538
539 // NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
540 // destroyed by the view hierarchy that contains it.
TEST_F(WidgetOwnershipTest,Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy)541 TEST_F(WidgetOwnershipTest,
542 Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
543 OwnershipTestState state;
544
545 Widget* toplevel = CreateTopLevelPlatformWidget();
546
547 Widget* widget = new OwnershipTestWidget(&state);
548 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
549 params.native_widget =
550 new OwnershipTestNativeWidgetAura(widget, &state);
551 params.parent = toplevel->GetNativeView();
552 widget->Init(params);
553
554 // Destroy the widget (achieved by closing the toplevel).
555 toplevel->CloseNow();
556
557 // The NativeWidget won't be deleted until after a return to the message loop
558 // so we have to run pending messages before testing the destruction status.
559 RunPendingMessages();
560
561 EXPECT_TRUE(state.widget_deleted);
562 EXPECT_TRUE(state.native_widget_deleted);
563 }
564
565 // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
566 // we close it directly.
TEST_F(WidgetOwnershipTest,Ownership_ViewsNativeWidgetOwnsWidget_Close)567 TEST_F(WidgetOwnershipTest,
568 Ownership_ViewsNativeWidgetOwnsWidget_Close) {
569 OwnershipTestState state;
570
571 Widget* toplevel = CreateTopLevelPlatformWidget();
572
573 Widget* widget = new OwnershipTestWidget(&state);
574 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
575 params.native_widget =
576 new OwnershipTestNativeWidgetAura(widget, &state);
577 params.parent = toplevel->GetNativeView();
578 widget->Init(params);
579
580 // Destroy the widget.
581 widget->Close();
582 toplevel->CloseNow();
583
584 // The NativeWidget won't be deleted until after a return to the message loop
585 // so we have to run pending messages before testing the destruction status.
586 RunPendingMessages();
587
588 EXPECT_TRUE(state.widget_deleted);
589 EXPECT_TRUE(state.native_widget_deleted);
590 }
591
592 // Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
TEST_F(WidgetOwnershipTest,Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView)593 TEST_F(WidgetOwnershipTest,
594 Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
595 OwnershipTestState state;
596
597 WidgetDelegateView* delegate_view = new WidgetDelegateView;
598
599 scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
600 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
601 params.native_widget =
602 new OwnershipTestNativeWidgetAura(widget.get(), &state);
603 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
604 params.delegate = delegate_view;
605 widget->Init(params);
606 widget->SetContentsView(delegate_view);
607
608 // Now delete the Widget. There should be no crash or use-after-free.
609 widget.reset();
610
611 EXPECT_TRUE(state.widget_deleted);
612 EXPECT_TRUE(state.native_widget_deleted);
613 }
614
615 ////////////////////////////////////////////////////////////////////////////////
616 // Test to verify using various Widget methods doesn't crash when the underlying
617 // NativeView is destroyed.
618 //
619 class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
620 public:
WidgetWithDestroyedNativeViewTest()621 WidgetWithDestroyedNativeViewTest() {}
~WidgetWithDestroyedNativeViewTest()622 virtual ~WidgetWithDestroyedNativeViewTest() {}
623
InvokeWidgetMethods(Widget * widget)624 void InvokeWidgetMethods(Widget* widget) {
625 widget->GetNativeView();
626 widget->GetNativeWindow();
627 ui::Accelerator accelerator;
628 widget->GetAccelerator(0, &accelerator);
629 widget->GetTopLevelWidget();
630 widget->GetWindowBoundsInScreen();
631 widget->GetClientAreaBoundsInScreen();
632 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
633 widget->SetSize(gfx::Size(10, 11));
634 widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
635 widget->SetVisibilityChangedAnimationsEnabled(false);
636 widget->StackAtTop();
637 widget->IsClosed();
638 widget->Close();
639 widget->Hide();
640 widget->Activate();
641 widget->Deactivate();
642 widget->IsActive();
643 widget->DisableInactiveRendering();
644 widget->SetAlwaysOnTop(true);
645 widget->IsAlwaysOnTop();
646 widget->Maximize();
647 widget->Minimize();
648 widget->Restore();
649 widget->IsMaximized();
650 widget->IsFullscreen();
651 widget->SetOpacity(0);
652 widget->SetUseDragFrame(true);
653 widget->FlashFrame(true);
654 widget->IsVisible();
655 widget->GetThemeProvider();
656 widget->GetNativeTheme();
657 widget->GetFocusManager();
658 widget->GetInputMethod();
659 widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
660 widget->IsMouseEventsEnabled();
661 widget->SetNativeWindowProperty("xx", widget);
662 widget->GetNativeWindowProperty("xx");
663 widget->GetFocusTraversable();
664 widget->GetLayer();
665 widget->ReorderNativeViews();
666 widget->SetCapture(widget->GetRootView());
667 widget->ReleaseCapture();
668 widget->HasCapture();
669 widget->GetWorkAreaBoundsInScreen();
670 widget->IsTranslucentWindowOpacitySupported();
671 }
672
673 private:
674 DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
675 };
676
TEST_F(WidgetWithDestroyedNativeViewTest,Test)677 TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
678 {
679 Widget widget;
680 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
681 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
682 widget.Init(params);
683 widget.Show();
684
685 widget.native_widget_private()->CloseNow();
686 InvokeWidgetMethods(&widget);
687 }
688 #if !defined(OS_CHROMEOS)
689 {
690 Widget widget;
691 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
692 params.native_widget = new PlatformDesktopNativeWidget(&widget);
693 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
694 widget.Init(params);
695 widget.Show();
696
697 widget.native_widget_private()->CloseNow();
698 InvokeWidgetMethods(&widget);
699 }
700 #endif
701 }
702
703 ////////////////////////////////////////////////////////////////////////////////
704 // Widget observer tests.
705 //
706
707 class WidgetObserverTest : public WidgetTest, public WidgetObserver {
708 public:
WidgetObserverTest()709 WidgetObserverTest()
710 : active_(NULL),
711 widget_closed_(NULL),
712 widget_activated_(NULL),
713 widget_shown_(NULL),
714 widget_hidden_(NULL),
715 widget_bounds_changed_(NULL) {
716 }
717
~WidgetObserverTest()718 virtual ~WidgetObserverTest() {}
719
720 // Overridden from WidgetObserver:
OnWidgetDestroying(Widget * widget)721 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
722 if (active_ == widget)
723 active_ = NULL;
724 widget_closed_ = widget;
725 }
726
OnWidgetActivationChanged(Widget * widget,bool active)727 virtual void OnWidgetActivationChanged(Widget* widget,
728 bool active) OVERRIDE {
729 if (active) {
730 if (widget_activated_)
731 widget_activated_->Deactivate();
732 widget_activated_ = widget;
733 active_ = widget;
734 } else {
735 if (widget_activated_ == widget)
736 widget_activated_ = NULL;
737 widget_deactivated_ = widget;
738 }
739 }
740
OnWidgetVisibilityChanged(Widget * widget,bool visible)741 virtual void OnWidgetVisibilityChanged(Widget* widget,
742 bool visible) OVERRIDE {
743 if (visible)
744 widget_shown_ = widget;
745 else
746 widget_hidden_ = widget;
747 }
748
OnWidgetBoundsChanged(Widget * widget,const gfx::Rect & new_bounds)749 virtual void OnWidgetBoundsChanged(Widget* widget,
750 const gfx::Rect& new_bounds) OVERRIDE {
751 widget_bounds_changed_ = widget;
752 }
753
reset()754 void reset() {
755 active_ = NULL;
756 widget_closed_ = NULL;
757 widget_activated_ = NULL;
758 widget_deactivated_ = NULL;
759 widget_shown_ = NULL;
760 widget_hidden_ = NULL;
761 widget_bounds_changed_ = NULL;
762 }
763
NewWidget()764 Widget* NewWidget() {
765 Widget* widget = CreateTopLevelNativeWidget();
766 widget->AddObserver(this);
767 return widget;
768 }
769
active() const770 const Widget* active() const { return active_; }
widget_closed() const771 const Widget* widget_closed() const { return widget_closed_; }
widget_activated() const772 const Widget* widget_activated() const { return widget_activated_; }
widget_deactivated() const773 const Widget* widget_deactivated() const { return widget_deactivated_; }
widget_shown() const774 const Widget* widget_shown() const { return widget_shown_; }
widget_hidden() const775 const Widget* widget_hidden() const { return widget_hidden_; }
widget_bounds_changed() const776 const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
777
778 private:
779 Widget* active_;
780
781 Widget* widget_closed_;
782 Widget* widget_activated_;
783 Widget* widget_deactivated_;
784 Widget* widget_shown_;
785 Widget* widget_hidden_;
786 Widget* widget_bounds_changed_;
787 };
788
TEST_F(WidgetObserverTest,DISABLED_ActivationChange)789 TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
790 Widget* toplevel = CreateTopLevelPlatformWidget();
791
792 Widget* toplevel1 = NewWidget();
793 Widget* toplevel2 = NewWidget();
794
795 toplevel1->Show();
796 toplevel2->Show();
797
798 reset();
799
800 toplevel1->Activate();
801
802 RunPendingMessages();
803 EXPECT_EQ(toplevel1, widget_activated());
804
805 toplevel2->Activate();
806 RunPendingMessages();
807 EXPECT_EQ(toplevel1, widget_deactivated());
808 EXPECT_EQ(toplevel2, widget_activated());
809 EXPECT_EQ(toplevel2, active());
810
811 toplevel->CloseNow();
812 }
813
TEST_F(WidgetObserverTest,DISABLED_VisibilityChange)814 TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
815 Widget* toplevel = CreateTopLevelPlatformWidget();
816
817 Widget* child1 = NewWidget();
818 Widget* child2 = NewWidget();
819
820 toplevel->Show();
821 child1->Show();
822 child2->Show();
823
824 reset();
825
826 child1->Hide();
827 EXPECT_EQ(child1, widget_hidden());
828
829 child2->Hide();
830 EXPECT_EQ(child2, widget_hidden());
831
832 child1->Show();
833 EXPECT_EQ(child1, widget_shown());
834
835 child2->Show();
836 EXPECT_EQ(child2, widget_shown());
837
838 toplevel->CloseNow();
839 }
840
TEST_F(WidgetObserverTest,DestroyBubble)841 TEST_F(WidgetObserverTest, DestroyBubble) {
842 Widget* anchor = CreateTopLevelPlatformWidget();
843 anchor->Show();
844
845 BubbleDelegateView* bubble_delegate =
846 new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
847 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
848 bubble_widget->Show();
849 bubble_widget->CloseNow();
850
851 anchor->Hide();
852 anchor->CloseNow();
853 }
854
TEST_F(WidgetObserverTest,WidgetBoundsChanged)855 TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
856 Widget* child1 = NewWidget();
857 Widget* child2 = NewWidget();
858
859 child1->OnNativeWidgetMove();
860 EXPECT_EQ(child1, widget_bounds_changed());
861
862 child2->OnNativeWidgetMove();
863 EXPECT_EQ(child2, widget_bounds_changed());
864
865 child1->OnNativeWidgetSizeChanged(gfx::Size());
866 EXPECT_EQ(child1, widget_bounds_changed());
867
868 child2->OnNativeWidgetSizeChanged(gfx::Size());
869 EXPECT_EQ(child2, widget_bounds_changed());
870 }
871
872 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the
873 // widget is visible and not maximized or fullscreen.
TEST_F(WidgetTest,GetWindowBoundsInScreen)874 TEST_F(WidgetTest, GetWindowBoundsInScreen) {
875 // Choose test coordinates away from edges and dimensions that are "small"
876 // (but not too small) to ensure the OS doesn't try to adjust them.
877 const gfx::Rect kTestBounds(150, 150, 400, 300);
878 const gfx::Size kTestSize(200, 180);
879
880 // First test a toplevel widget.
881 Widget* widget = CreateTopLevelPlatformWidget();
882 widget->Show();
883
884 EXPECT_NE(kTestSize.ToString(),
885 widget->GetWindowBoundsInScreen().size().ToString());
886 widget->SetSize(kTestSize);
887 EXPECT_EQ(kTestSize.ToString(),
888 widget->GetWindowBoundsInScreen().size().ToString());
889
890 EXPECT_NE(kTestBounds.ToString(),
891 widget->GetWindowBoundsInScreen().ToString());
892 widget->SetBounds(kTestBounds);
893 EXPECT_EQ(kTestBounds.ToString(),
894 widget->GetWindowBoundsInScreen().ToString());
895
896 // Changing just the size should not change the origin.
897 widget->SetSize(kTestSize);
898 EXPECT_EQ(kTestBounds.origin().ToString(),
899 widget->GetWindowBoundsInScreen().origin().ToString());
900
901 widget->CloseNow();
902
903 // Same tests with a frameless window.
904 widget = CreateTopLevelFramelessPlatformWidget();
905 widget->Show();
906
907 EXPECT_NE(kTestSize.ToString(),
908 widget->GetWindowBoundsInScreen().size().ToString());
909 widget->SetSize(kTestSize);
910 EXPECT_EQ(kTestSize.ToString(),
911 widget->GetWindowBoundsInScreen().size().ToString());
912
913 EXPECT_NE(kTestBounds.ToString(),
914 widget->GetWindowBoundsInScreen().ToString());
915 widget->SetBounds(kTestBounds);
916 EXPECT_EQ(kTestBounds.ToString(),
917 widget->GetWindowBoundsInScreen().ToString());
918
919 // For a frameless widget, the client bounds should also match.
920 EXPECT_EQ(kTestBounds.ToString(),
921 widget->GetClientAreaBoundsInScreen().ToString());
922
923 // Verify origin is stable for a frameless window as well.
924 widget->SetSize(kTestSize);
925 EXPECT_EQ(kTestBounds.origin().ToString(),
926 widget->GetWindowBoundsInScreen().origin().ToString());
927
928 widget->CloseNow();
929 }
930
931 #if defined(false)
932 // Aura needs shell to maximize/fullscreen window.
933 // NativeWidgetGtk doesn't implement GetRestoredBounds.
TEST_F(WidgetTest,GetRestoredBounds)934 TEST_F(WidgetTest, GetRestoredBounds) {
935 Widget* toplevel = CreateTopLevelPlatformWidget();
936 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
937 toplevel->GetRestoredBounds().ToString());
938 toplevel->Show();
939 toplevel->Maximize();
940 RunPendingMessages();
941 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
942 toplevel->GetRestoredBounds().ToString());
943 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
944 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
945
946 toplevel->Restore();
947 RunPendingMessages();
948 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
949 toplevel->GetRestoredBounds().ToString());
950
951 toplevel->SetFullscreen(true);
952 RunPendingMessages();
953 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
954 toplevel->GetRestoredBounds().ToString());
955 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
956 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
957 }
958 #endif
959
960 // Test that window state is not changed after getting out of full screen.
TEST_F(WidgetTest,ExitFullscreenRestoreState)961 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
962 Widget* toplevel = CreateTopLevelPlatformWidget();
963
964 toplevel->Show();
965 RunPendingMessages();
966
967 // This should be a normal state window.
968 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
969
970 toplevel->SetFullscreen(true);
971 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
972 toplevel->SetFullscreen(false);
973 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
974
975 // And it should still be in normal state after getting out of full screen.
976 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
977
978 // Now, make it maximized.
979 toplevel->Maximize();
980 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
981
982 toplevel->SetFullscreen(true);
983 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
984 toplevel->SetFullscreen(false);
985 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
986
987 // And it stays maximized after getting out of full screen.
988 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
989
990 // Clean up.
991 toplevel->Close();
992 RunPendingMessages();
993 }
994
995 // The key-event propagation from Widget happens differently on aura and
996 // non-aura systems because of the difference in IME. So this test works only on
997 // aura.
TEST_F(WidgetTest,KeyboardInputEvent)998 TEST_F(WidgetTest, KeyboardInputEvent) {
999 Widget* toplevel = CreateTopLevelPlatformWidget();
1000 View* container = toplevel->client_view();
1001
1002 Textfield* textfield = new Textfield();
1003 textfield->SetText(base::ASCIIToUTF16("some text"));
1004 container->AddChildView(textfield);
1005 toplevel->Show();
1006 textfield->RequestFocus();
1007
1008 // The press gets handled. The release doesn't have an effect.
1009 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1010 toplevel->OnKeyEvent(&backspace_p);
1011 EXPECT_TRUE(backspace_p.stopped_propagation());
1012 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1013 toplevel->OnKeyEvent(&backspace_r);
1014 EXPECT_FALSE(backspace_r.handled());
1015
1016 toplevel->Close();
1017 }
1018
1019 // Verifies bubbles result in a focus lost when shown.
1020 // TODO(msw): this tests relies on focus, it needs to be in
1021 // interactive_ui_tests.
TEST_F(WidgetTest,DISABLED_FocusChangesOnBubble)1022 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1023 // Create a widget, show and activate it and focus the contents view.
1024 View* contents_view = new View;
1025 contents_view->SetFocusable(true);
1026 Widget widget;
1027 Widget::InitParams init_params =
1028 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1029 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1030 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1031 #if !defined(OS_CHROMEOS)
1032 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1033 #endif
1034 widget.Init(init_params);
1035 widget.SetContentsView(contents_view);
1036 widget.Show();
1037 widget.Activate();
1038 contents_view->RequestFocus();
1039 EXPECT_TRUE(contents_view->HasFocus());
1040
1041 // Show a bubble.
1042 BubbleDelegateView* bubble_delegate_view =
1043 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1044 bubble_delegate_view->SetFocusable(true);
1045 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1046 bubble_delegate_view->RequestFocus();
1047
1048 // |contents_view_| should no longer have focus.
1049 EXPECT_FALSE(contents_view->HasFocus());
1050 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1051
1052 bubble_delegate_view->GetWidget()->CloseNow();
1053
1054 // Closing the bubble should result in focus going back to the contents view.
1055 EXPECT_TRUE(contents_view->HasFocus());
1056 }
1057
1058 class TestBubbleDelegateView : public BubbleDelegateView {
1059 public:
TestBubbleDelegateView(View * anchor)1060 TestBubbleDelegateView(View* anchor)
1061 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1062 reset_controls_called_(false) {}
~TestBubbleDelegateView()1063 virtual ~TestBubbleDelegateView() {}
1064
ShouldShowCloseButton() const1065 virtual bool ShouldShowCloseButton() const OVERRIDE {
1066 reset_controls_called_ = true;
1067 return true;
1068 }
1069
1070 mutable bool reset_controls_called_;
1071 };
1072
TEST_F(WidgetTest,BubbleControlsResetOnInit)1073 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1074 Widget* anchor = CreateTopLevelPlatformWidget();
1075 anchor->Show();
1076
1077 TestBubbleDelegateView* bubble_delegate =
1078 new TestBubbleDelegateView(anchor->client_view());
1079 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1080 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1081 bubble_widget->Show();
1082 bubble_widget->CloseNow();
1083
1084 anchor->Hide();
1085 anchor->CloseNow();
1086 }
1087
1088 // Desktop native widget Aura tests are for non Chrome OS platforms.
1089 #if !defined(OS_CHROMEOS)
1090 // Test to ensure that after minimize, view width is set to zero.
TEST_F(WidgetTest,TestViewWidthAfterMinimizingWidget)1091 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1092 // Create a widget.
1093 Widget widget;
1094 Widget::InitParams init_params =
1095 CreateParams(Widget::InitParams::TYPE_WINDOW);
1096 init_params.show_state = ui::SHOW_STATE_NORMAL;
1097 gfx::Rect initial_bounds(0, 0, 300, 400);
1098 init_params.bounds = initial_bounds;
1099 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1100 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1101 widget.Init(init_params);
1102 NonClientView* non_client_view = widget.non_client_view();
1103 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1104 non_client_view->SetFrameView(frame_view);
1105 widget.Show();
1106 widget.Minimize();
1107 EXPECT_EQ(0, frame_view->width());
1108 }
1109
1110 // This class validates whether paints are received for a visible Widget.
1111 // To achieve this it overrides the Show and Close methods on the Widget class
1112 // and sets state whether subsequent paints are expected.
1113 class DesktopAuraTestValidPaintWidget : public views::Widget {
1114 public:
DesktopAuraTestValidPaintWidget()1115 DesktopAuraTestValidPaintWidget()
1116 : expect_paint_(true),
1117 received_paint_while_hidden_(false) {
1118 }
1119
~DesktopAuraTestValidPaintWidget()1120 virtual ~DesktopAuraTestValidPaintWidget() {
1121 }
1122
Show()1123 virtual void Show() OVERRIDE {
1124 expect_paint_ = true;
1125 views::Widget::Show();
1126 }
1127
Close()1128 virtual void Close() OVERRIDE {
1129 expect_paint_ = false;
1130 views::Widget::Close();
1131 }
1132
Hide()1133 void Hide() {
1134 expect_paint_ = false;
1135 views::Widget::Hide();
1136 }
1137
OnNativeWidgetPaint(gfx::Canvas * canvas)1138 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
1139 EXPECT_TRUE(expect_paint_);
1140 if (!expect_paint_)
1141 received_paint_while_hidden_ = true;
1142 views::Widget::OnNativeWidgetPaint(canvas);
1143 }
1144
received_paint_while_hidden() const1145 bool received_paint_while_hidden() const {
1146 return received_paint_while_hidden_;
1147 }
1148
1149 private:
1150 bool expect_paint_;
1151 bool received_paint_while_hidden_;
1152 };
1153
TEST_F(WidgetTest,DesktopNativeWidgetNoPaintAfterCloseTest)1154 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1155 View* contents_view = new View;
1156 contents_view->SetFocusable(true);
1157 DesktopAuraTestValidPaintWidget widget;
1158 Widget::InitParams init_params =
1159 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1160 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1161 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1162 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1163 widget.Init(init_params);
1164 widget.SetContentsView(contents_view);
1165 widget.Show();
1166 widget.Activate();
1167 RunPendingMessages();
1168 widget.SchedulePaintInRect(init_params.bounds);
1169 widget.Close();
1170 RunPendingMessages();
1171 EXPECT_FALSE(widget.received_paint_while_hidden());
1172 }
1173
TEST_F(WidgetTest,DesktopNativeWidgetNoPaintAfterHideTest)1174 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1175 View* contents_view = new View;
1176 contents_view->SetFocusable(true);
1177 DesktopAuraTestValidPaintWidget widget;
1178 Widget::InitParams init_params =
1179 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1180 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1181 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1182 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1183 widget.Init(init_params);
1184 widget.SetContentsView(contents_view);
1185 widget.Show();
1186 widget.Activate();
1187 RunPendingMessages();
1188 widget.SchedulePaintInRect(init_params.bounds);
1189 widget.Hide();
1190 RunPendingMessages();
1191 EXPECT_FALSE(widget.received_paint_while_hidden());
1192 widget.Close();
1193 }
1194
1195 // Test to ensure that the aura Window's visiblity state is set to visible if
1196 // the underlying widget is hidden and then shown.
TEST_F(WidgetTest,TestWindowVisibilityAfterHide)1197 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1198 // Create a widget.
1199 Widget widget;
1200 Widget::InitParams init_params =
1201 CreateParams(Widget::InitParams::TYPE_WINDOW);
1202 init_params.show_state = ui::SHOW_STATE_NORMAL;
1203 gfx::Rect initial_bounds(0, 0, 300, 400);
1204 init_params.bounds = initial_bounds;
1205 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1206 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1207 widget.Init(init_params);
1208 NonClientView* non_client_view = widget.non_client_view();
1209 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1210 non_client_view->SetFrameView(frame_view);
1211
1212 widget.Hide();
1213 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1214 widget.Show();
1215 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1216 }
1217
1218 // The following code verifies we can correctly destroy a Widget from a mouse
1219 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1220 // nested message loops from such events, nor has the code ever really dealt
1221 // with this situation.
1222
1223 // Generates two moves (first generates enter, second real move), a press, drag
1224 // and release stopping at |last_event_type|.
GenerateMouseEvents(Widget * widget,ui::EventType last_event_type)1225 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1226 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1227 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1228 screen_bounds.CenterPoint(), 0, 0);
1229 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1230 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1231 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1232 return;
1233 details = dispatcher->OnEventFromSource(&move_event);
1234 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1235 return;
1236
1237 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1238 screen_bounds.CenterPoint(), 0, 0);
1239 details = dispatcher->OnEventFromSource(&press_event);
1240 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1241 return;
1242
1243 gfx::Point end_point(screen_bounds.CenterPoint());
1244 end_point.Offset(1, 1);
1245 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1246 details = dispatcher->OnEventFromSource(&drag_event);
1247 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1248 return;
1249
1250 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1251 0);
1252 details = dispatcher->OnEventFromSource(&release_event);
1253 if (details.dispatcher_destroyed)
1254 return;
1255 }
1256
1257 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
RunCloseWidgetDuringDispatchTest(WidgetTest * test,ui::EventType last_event_type)1258 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1259 ui::EventType last_event_type) {
1260 // |widget| is deleted by CloseWidgetView.
1261 Widget* widget = new Widget;
1262 Widget::InitParams params =
1263 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1264 params.native_widget = new PlatformDesktopNativeWidget(widget);
1265 params.bounds = gfx::Rect(0, 0, 50, 100);
1266 widget->Init(params);
1267 widget->SetContentsView(new CloseWidgetView(last_event_type));
1268 widget->Show();
1269 GenerateMouseEvents(widget, last_event_type);
1270 }
1271
1272 // Verifies deleting the widget from a mouse pressed event doesn't crash.
TEST_F(WidgetTest,CloseWidgetDuringMousePress)1273 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1274 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1275 }
1276
1277 // Verifies deleting the widget from a mouse released event doesn't crash.
TEST_F(WidgetTest,CloseWidgetDuringMouseReleased)1278 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1279 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1280 }
1281
1282 #endif // !defined(OS_CHROMEOS)
1283
1284 // Tests that wheel events generated from scroll events are targetted to the
1285 // views under the cursor when the focused view does not processed them.
TEST_F(WidgetTest,WheelEventsFromScrollEventTarget)1286 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1287 EventCountView* cursor_view = new EventCountView;
1288 cursor_view->SetBounds(60, 0, 50, 40);
1289
1290 Widget* widget = CreateTopLevelPlatformWidget();
1291 widget->GetRootView()->AddChildView(cursor_view);
1292
1293 // Generate a scroll event on the cursor view.
1294 ui::ScrollEvent scroll(ui::ET_SCROLL,
1295 gfx::Point(65, 5),
1296 ui::EventTimeForNow(),
1297 0,
1298 0, 20,
1299 0, 20,
1300 2);
1301 widget->OnScrollEvent(&scroll);
1302
1303 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1304 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1305
1306 cursor_view->ResetCounts();
1307
1308 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1309 gfx::Point(5, 5),
1310 ui::EventTimeForNow(),
1311 0,
1312 0, 20,
1313 0, 20,
1314 2);
1315 widget->OnScrollEvent(&scroll2);
1316
1317 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1318 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1319
1320 widget->CloseNow();
1321 }
1322
1323 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1324 // events are not dispatched to any view.
TEST_F(WidgetTest,GestureScrollEventDispatching)1325 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1326 EventCountView* noscroll_view = new EventCountView;
1327 EventCountView* scroll_view = new ScrollableEventCountView;
1328
1329 noscroll_view->SetBounds(0, 0, 50, 40);
1330 scroll_view->SetBounds(60, 0, 40, 40);
1331
1332 Widget* widget = CreateTopLevelPlatformWidget();
1333 widget->GetRootView()->AddChildView(noscroll_view);
1334 widget->GetRootView()->AddChildView(scroll_view);
1335
1336 {
1337 ui::GestureEvent begin(
1338 5,
1339 5,
1340 0,
1341 base::TimeDelta(),
1342 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1343 widget->OnGestureEvent(&begin);
1344 ui::GestureEvent update(
1345 25,
1346 15,
1347 0,
1348 base::TimeDelta(),
1349 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1350 widget->OnGestureEvent(&update);
1351 ui::GestureEvent end(25,
1352 15,
1353 0,
1354 base::TimeDelta(),
1355 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1356 widget->OnGestureEvent(&end);
1357
1358 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1359 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1360 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1361 }
1362
1363 {
1364 ui::GestureEvent begin(
1365 65,
1366 5,
1367 0,
1368 base::TimeDelta(),
1369 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1370 widget->OnGestureEvent(&begin);
1371 ui::GestureEvent update(
1372 85,
1373 15,
1374 0,
1375 base::TimeDelta(),
1376 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1377 widget->OnGestureEvent(&update);
1378 ui::GestureEvent end(85,
1379 15,
1380 0,
1381 base::TimeDelta(),
1382 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1383 widget->OnGestureEvent(&end);
1384
1385 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1386 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1387 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1388 }
1389
1390 widget->CloseNow();
1391 }
1392
1393 // Tests that event-handlers installed on the RootView get triggered correctly.
1394 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
TEST_F(WidgetTest,EventHandlersOnRootView)1395 TEST_F(WidgetTest, EventHandlersOnRootView) {
1396 Widget* widget = CreateTopLevelNativeWidget();
1397 View* root_view = widget->GetRootView();
1398
1399 scoped_ptr<EventCountView> view(new EventCountView());
1400 view->set_owned_by_client();
1401 view->SetBounds(0, 0, 20, 20);
1402 root_view->AddChildView(view.get());
1403
1404 EventCountHandler h1;
1405 root_view->AddPreTargetHandler(&h1);
1406
1407 EventCountHandler h2;
1408 root_view->AddPostTargetHandler(&h2);
1409
1410 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1411 widget->Show();
1412
1413 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1414 // bubble up the views hierarchy to be re-dispatched on the root view.
1415 ui::ScrollEvent scroll(ui::ET_SCROLL,
1416 gfx::Point(5, 5),
1417 ui::EventTimeForNow(),
1418 0,
1419 0, 20,
1420 0, 20,
1421 2);
1422 widget->OnScrollEvent(&scroll);
1423 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1424 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1425 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1426
1427 // Unhandled scroll events are turned into wheel events and re-dispatched.
1428 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1429 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1430 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1431
1432 h1.ResetCounts();
1433 view->ResetCounts();
1434 h2.ResetCounts();
1435
1436 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1437 // should bubble up the views hierarchy to be re-dispatched on the root view.
1438 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1439 gfx::Point(5, 5),
1440 ui::EventTimeForNow(),
1441 0,
1442 0, 20,
1443 0, 20,
1444 2);
1445 widget->OnScrollEvent(&fling);
1446 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1447 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1448 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1449
1450 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1451 // be turned into wheel events and re-dispatched.
1452 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1453 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1454 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1455
1456 h1.ResetCounts();
1457 view->ResetCounts();
1458 h2.ResetCounts();
1459
1460 // Change the handle mode of |view| so that events are marked as handled at
1461 // the target phase.
1462 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1463
1464 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1465 // The events are handled at the target phase and should not reach the
1466 // post-target handler.
1467 ui::GestureEvent tap_down(5,
1468 5,
1469 0,
1470 ui::EventTimeForNow(),
1471 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1472 widget->OnGestureEvent(&tap_down);
1473 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1474 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1475 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1476
1477 ui::GestureEvent tap_cancel(
1478 5,
1479 5,
1480 0,
1481 ui::EventTimeForNow(),
1482 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1483 widget->OnGestureEvent(&tap_cancel);
1484 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1485 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1486 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1487
1488 h1.ResetCounts();
1489 view->ResetCounts();
1490 h2.ResetCounts();
1491
1492 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1493 // and should not reach the post-target handler.
1494 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1495 gfx::Point(5, 5),
1496 ui::EventTimeForNow(),
1497 0,
1498 0, 20,
1499 0, 20,
1500 2);
1501 widget->OnScrollEvent(&consumed_scroll);
1502 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1503 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1504 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1505
1506 // Handled scroll events are not turned into wheel events and re-dispatched.
1507 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1508 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1509 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1510
1511 widget->CloseNow();
1512 }
1513
TEST_F(WidgetTest,SynthesizeMouseMoveEvent)1514 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1515 Widget* widget = CreateTopLevelNativeWidget();
1516 View* root_view = widget->GetRootView();
1517
1518 EventCountView* v1 = new EventCountView();
1519 v1->SetBounds(0, 0, 10, 10);
1520 root_view->AddChildView(v1);
1521 EventCountView* v2 = new EventCountView();
1522 v2->SetBounds(0, 10, 10, 10);
1523 root_view->AddChildView(v2);
1524
1525 gfx::Point cursor_location(5, 5);
1526 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1527 ui::EF_NONE, ui::EF_NONE);
1528 widget->OnMouseEvent(&move);
1529
1530 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1531 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1532
1533 delete v1;
1534 v2->SetBounds(0, 0, 10, 10);
1535 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1536
1537 widget->SynthesizeMouseMoveEvent();
1538 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1539 }
1540
1541 namespace {
1542
1543 // ui::EventHandler which handles all mouse press events.
1544 class MousePressEventConsumer : public ui::EventHandler {
1545 public:
MousePressEventConsumer()1546 explicit MousePressEventConsumer() {
1547 }
1548
~MousePressEventConsumer()1549 virtual ~MousePressEventConsumer() {
1550 }
1551
1552 private:
1553 // ui::EventHandler:
OnMouseEvent(ui::MouseEvent * event)1554 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1555 if (event->type() == ui::ET_MOUSE_PRESSED)
1556 event->SetHandled();
1557 }
1558
1559 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1560 };
1561
1562 } // namespace
1563
1564 // Test that mouse presses and mouse releases are dispatched normally when a
1565 // touch is down.
TEST_F(WidgetTest,MouseEventDispatchWhileTouchIsDown)1566 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1567 Widget* widget = CreateTopLevelNativeWidget();
1568 widget->Show();
1569 widget->SetSize(gfx::Size(300, 300));
1570
1571 EventCountView* event_count_view = new EventCountView();
1572 event_count_view->SetBounds(0, 0, 300, 300);
1573 widget->GetRootView()->AddChildView(event_count_view);
1574
1575 MousePressEventConsumer consumer;
1576 event_count_view->AddPostTargetHandler(&consumer);
1577
1578 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1579 generator.PressTouch();
1580 generator.ClickLeftButton();
1581
1582 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1583 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1584
1585 widget->CloseNow();
1586 }
1587
1588 // Used by SingleWindowClosing to count number of times WindowClosing() has
1589 // been invoked.
1590 class ClosingDelegate : public WidgetDelegate {
1591 public:
ClosingDelegate()1592 ClosingDelegate() : count_(0), widget_(NULL) {}
1593
count() const1594 int count() const { return count_; }
1595
set_widget(views::Widget * widget)1596 void set_widget(views::Widget* widget) { widget_ = widget; }
1597
1598 // WidgetDelegate overrides:
GetWidget()1599 virtual Widget* GetWidget() OVERRIDE { return widget_; }
GetWidget() const1600 virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
WindowClosing()1601 virtual void WindowClosing() OVERRIDE {
1602 count_++;
1603 }
1604
1605 private:
1606 int count_;
1607 views::Widget* widget_;
1608
1609 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1610 };
1611
1612 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1613 // is closed.
TEST_F(WidgetTest,SingleWindowClosing)1614 TEST_F(WidgetTest, SingleWindowClosing) {
1615 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1616 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1617 Widget::InitParams init_params =
1618 CreateParams(Widget::InitParams::TYPE_WINDOW);
1619 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1620 init_params.delegate = delegate.get();
1621 #if !defined(OS_CHROMEOS)
1622 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1623 #endif
1624 widget->Init(init_params);
1625 EXPECT_EQ(0, delegate->count());
1626 widget->CloseNow();
1627 EXPECT_EQ(1, delegate->count());
1628 }
1629
1630 class WidgetWindowTitleTest : public WidgetTest {
1631 protected:
RunTest(bool desktop_native_widget)1632 void RunTest(bool desktop_native_widget) {
1633 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1634 Widget::InitParams init_params =
1635 CreateParams(Widget::InitParams::TYPE_WINDOW);
1636 widget->Init(init_params);
1637
1638 #if !defined(OS_CHROMEOS)
1639 if (desktop_native_widget)
1640 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1641 #else
1642 DCHECK(!desktop_native_widget)
1643 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1644 #endif
1645
1646 internal::NativeWidgetPrivate* native_widget =
1647 widget->native_widget_private();
1648
1649 base::string16 empty;
1650 base::string16 s1(base::UTF8ToUTF16("Title1"));
1651 base::string16 s2(base::UTF8ToUTF16("Title2"));
1652 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1653
1654 // The widget starts with no title, setting empty should not change
1655 // anything.
1656 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1657 // Setting the title to something non-empty should cause a change.
1658 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1659 // Setting the title to something else with the same length should cause a
1660 // change.
1661 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1662 // Setting the title to something else with a different length should cause
1663 // a change.
1664 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1665 // Setting the title to the same thing twice should not cause a change.
1666 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1667
1668 widget->CloseNow();
1669 }
1670 };
1671
TEST_F(WidgetWindowTitleTest,SetWindowTitleChanged_NativeWidget)1672 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1673 // Use the default NativeWidget.
1674 bool desktop_native_widget = false;
1675 RunTest(desktop_native_widget);
1676 }
1677
1678 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1679 #if !defined(OS_CHROMEOS)
TEST_F(WidgetWindowTitleTest,SetWindowTitleChanged_DesktopNativeWidget)1680 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1681 // Override to use a DesktopNativeWidget.
1682 bool desktop_native_widget = true;
1683 RunTest(desktop_native_widget);
1684 }
1685 #endif // !OS_CHROMEOS
1686
TEST_F(WidgetTest,WidgetDeleted_InOnMousePressed)1687 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1688 Widget* widget = new Widget;
1689 Widget::InitParams params =
1690 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1691 widget->Init(params);
1692
1693 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1694
1695 widget->SetSize(gfx::Size(100, 100));
1696 widget->Show();
1697
1698 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1699
1700 WidgetDeletionObserver deletion_observer(widget);
1701 generator.ClickLeftButton();
1702 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1703
1704 // Yay we did not crash!
1705 }
1706
TEST_F(WidgetTest,WidgetDeleted_InDispatchGestureEvent)1707 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1708 Widget* widget = new Widget;
1709 Widget::InitParams params =
1710 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1711 widget->Init(params);
1712
1713 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1714
1715 widget->SetSize(gfx::Size(100, 100));
1716 widget->Show();
1717
1718 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1719
1720 WidgetDeletionObserver deletion_observer(widget);
1721 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1722 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1723
1724 // Yay we did not crash!
1725 }
1726
1727 // See description of RunGetNativeThemeFromDestructor() for details.
1728 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1729 public:
GetNativeThemeFromDestructorView()1730 GetNativeThemeFromDestructorView() {}
~GetNativeThemeFromDestructorView()1731 virtual ~GetNativeThemeFromDestructorView() {
1732 VerifyNativeTheme();
1733 }
1734
GetContentsView()1735 virtual View* GetContentsView() OVERRIDE {
1736 return this;
1737 }
1738
1739 private:
VerifyNativeTheme()1740 void VerifyNativeTheme() {
1741 ASSERT_TRUE(GetNativeTheme() != NULL);
1742 }
1743
1744 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1745 };
1746
1747 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1748 // crash. |is_first_run| is true if this is the first call. A return value of
1749 // true indicates this should be run again with a value of false.
1750 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
RunGetNativeThemeFromDestructor(const Widget::InitParams & in_params,bool is_first_run)1751 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1752 bool is_first_run) {
1753 bool needs_second_run = false;
1754 // Destroyed by CloseNow() below.
1755 Widget* widget = new Widget;
1756 Widget::InitParams params(in_params);
1757 // Deletes itself when the Widget is destroyed.
1758 params.delegate = new GetNativeThemeFromDestructorView;
1759 #if !defined(OS_CHROMEOS)
1760 if (is_first_run) {
1761 params.native_widget = new PlatformDesktopNativeWidget(widget);
1762 needs_second_run = true;
1763 }
1764 #endif
1765 widget->Init(params);
1766 widget->CloseNow();
1767 return needs_second_run;
1768 }
1769
1770 // See description of RunGetNativeThemeFromDestructor() for details.
TEST_F(WidgetTest,GetNativeThemeFromDestructor)1771 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1772 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1773 if (RunGetNativeThemeFromDestructor(params, true))
1774 RunGetNativeThemeFromDestructor(params, false);
1775 }
1776
1777 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1778 // destroyed.
1779 class CloseDestroysWidget : public Widget {
1780 public:
CloseDestroysWidget(bool * destroyed)1781 explicit CloseDestroysWidget(bool* destroyed)
1782 : destroyed_(destroyed) {
1783 }
1784
~CloseDestroysWidget()1785 virtual ~CloseDestroysWidget() {
1786 if (destroyed_) {
1787 *destroyed_ = true;
1788 base::MessageLoop::current()->QuitNow();
1789 }
1790 }
1791
Detach()1792 void Detach() { destroyed_ = NULL; }
1793
1794 private:
1795 // If non-null set to true from destructor.
1796 bool* destroyed_;
1797
1798 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1799 };
1800
1801 // An observer that registers that an animation has ended.
1802 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1803 public:
AnimationEndObserver()1804 AnimationEndObserver() : animation_completed_(false) {}
~AnimationEndObserver()1805 virtual ~AnimationEndObserver() {}
1806
animation_completed() const1807 bool animation_completed() const { return animation_completed_; }
1808
1809 // ui::ImplicitAnimationObserver:
OnImplicitAnimationsCompleted()1810 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
1811 animation_completed_ = true;
1812 }
1813
1814 private:
1815 bool animation_completed_;
1816
1817 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1818 };
1819
1820 // An observer that registers the bounds of a widget on destruction.
1821 class WidgetBoundsObserver : public WidgetObserver {
1822 public:
WidgetBoundsObserver()1823 WidgetBoundsObserver() {}
~WidgetBoundsObserver()1824 virtual ~WidgetBoundsObserver() {}
1825
bounds()1826 gfx::Rect bounds() { return bounds_; }
1827
1828 // WidgetObserver:
OnWidgetDestroying(Widget * widget)1829 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
1830 bounds_ = widget->GetWindowBoundsInScreen();
1831 }
1832
1833 private:
1834 gfx::Rect bounds_;
1835
1836 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1837 };
1838
1839 // Verifies Close() results in destroying.
TEST_F(WidgetTest,CloseDestroys)1840 TEST_F(WidgetTest, CloseDestroys) {
1841 bool destroyed = false;
1842 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1843 Widget::InitParams params =
1844 CreateParams(views::Widget::InitParams::TYPE_MENU);
1845 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1846 #if !defined(OS_CHROMEOS)
1847 params.native_widget = new PlatformDesktopNativeWidget(widget);
1848 #endif
1849 widget->Init(params);
1850 widget->Show();
1851 widget->Hide();
1852 widget->Close();
1853 EXPECT_FALSE(destroyed);
1854 // Run the message loop as Close() asynchronously deletes.
1855 base::RunLoop().Run();
1856 EXPECT_TRUE(destroyed);
1857 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1858 if (!destroyed) {
1859 widget->Detach();
1860 widget->CloseNow();
1861 }
1862 }
1863
1864 // Tests that killing a widget while animating it does not crash.
TEST_F(WidgetTest,CloseWidgetWhileAnimating)1865 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1866 scoped_ptr<Widget> widget(new Widget);
1867 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1868 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1869 params.bounds = gfx::Rect(50, 50, 250, 250);
1870 widget->Init(params);
1871 AnimationEndObserver animation_observer;
1872 WidgetBoundsObserver widget_observer;
1873 gfx::Rect bounds(0, 0, 50, 50);
1874 {
1875 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1876 // animating the movement.
1877 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1878 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1879 ui::ScopedLayerAnimationSettings animation_settings(
1880 widget->GetLayer()->GetAnimator());
1881 animation_settings.AddObserver(&animation_observer);
1882 widget->AddObserver(&widget_observer);
1883 widget->Show();
1884
1885 // Animate the bounds change.
1886 widget->SetBounds(bounds);
1887 widget.reset();
1888 EXPECT_FALSE(animation_observer.animation_completed());
1889 }
1890 EXPECT_TRUE(animation_observer.animation_completed());
1891 EXPECT_EQ(widget_observer.bounds(), bounds);
1892 }
1893
1894 // A view that consumes mouse-pressed event and gesture-tap-down events.
1895 class RootViewTestView : public View {
1896 public:
RootViewTestView()1897 RootViewTestView(): View() {}
1898
1899 private:
OnMousePressed(const ui::MouseEvent & event)1900 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
1901 return true;
1902 }
1903
OnGestureEvent(ui::GestureEvent * event)1904 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1905 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1906 event->SetHandled();
1907 }
1908 };
1909
1910 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1911 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1912 #if defined(OS_WIN)
1913 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1914 DISABLED_TestRootViewHandlersWhenHidden
1915 #else
1916 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1917 TestRootViewHandlersWhenHidden
1918 #endif
TEST_F(WidgetTest,MAYBE_DisableTestRootViewHandlersWhenHidden)1919 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1920 Widget* widget = CreateTopLevelNativeWidget();
1921 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1922 View* view = new RootViewTestView();
1923 view->SetBounds(0, 0, 300, 300);
1924 internal::RootView* root_view =
1925 static_cast<internal::RootView*>(widget->GetRootView());
1926 root_view->AddChildView(view);
1927
1928 // Check RootView::mouse_pressed_handler_.
1929 widget->Show();
1930 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1931 gfx::Point click_location(45, 15);
1932 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1933 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1934 widget->OnMouseEvent(&press);
1935 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1936 widget->Hide();
1937 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1938
1939 // Check RootView::mouse_move_handler_.
1940 widget->Show();
1941 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1942 gfx::Point move_location(45, 15);
1943 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1944 widget->OnMouseEvent(&move);
1945 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1946 widget->Hide();
1947 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1948
1949 // Check RootView::gesture_handler_.
1950 widget->Show();
1951 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1952 ui::GestureEvent tap_down(15,
1953 15,
1954 0,
1955 base::TimeDelta(),
1956 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1957 widget->OnGestureEvent(&tap_down);
1958 EXPECT_EQ(view, GetGestureHandler(root_view));
1959 widget->Hide();
1960 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1961
1962 widget->Close();
1963 }
1964
1965 // Convenience to make constructing a GestureEvent simpler.
1966 class GestureEventForTest : public ui::GestureEvent {
1967 public:
GestureEventForTest(ui::EventType type,int x,int y)1968 GestureEventForTest(ui::EventType type, int x, int y)
1969 : GestureEvent(x,
1970 y,
1971 0,
1972 base::TimeDelta(),
1973 ui::GestureEventDetails(type)) {}
1974
GestureEventForTest(ui::GestureEventDetails details,int x,int y)1975 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
1976 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
1977 };
1978
1979 // Tests that the |gesture_handler_| member in RootView is always NULL
1980 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
1981 // the release of the final touch point on the screen and that
1982 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
1983 // point are never dispatched to a view. Also verifies that
1984 // ui::ET_GESTURE_BEGIN is never dispatched to a view and does not change the
1985 // value of |gesture_handler_|.
TEST_F(WidgetTest,GestureBeginAndEndEvents)1986 TEST_F(WidgetTest, GestureBeginAndEndEvents) {
1987 Widget* widget = CreateTopLevelNativeWidget();
1988 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1989 EventCountView* view = new EventCountView();
1990 view->SetBounds(0, 0, 300, 300);
1991 internal::RootView* root_view =
1992 static_cast<internal::RootView*>(widget->GetRootView());
1993 root_view->AddChildView(view);
1994 widget->Show();
1995
1996 // If no gesture handler is set, dispatching a ui::ET_GESTURE_END or
1997 // ui::ET_GESTURE_BEGIN event should not set the gesture handler and
1998 // the events should remain unhandled because the handle mode of |view|
1999 // indicates that events should not be consumed.
2000 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2001 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2002 widget->OnGestureEvent(&end);
2003 EXPECT_FALSE(end.handled());
2004 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2005
2006 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 15, 15);
2007 widget->OnGestureEvent(&begin);
2008 EXPECT_FALSE(begin.handled());
2009 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2010
2011 // Change the handle mode of |view| to indicate that it would like
2012 // to handle all events.
2013 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2014
2015 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2016 // should not set the gesture handler and should not be marked as handled
2017 // because it is never dispatched.
2018 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2019 widget->OnGestureEvent(&begin);
2020 EXPECT_FALSE(begin.handled());
2021 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2022
2023 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_BEGIN
2024 // corresponding to a second touch point should not set the gesture handler
2025 // and should not be marked as handled because it is never dispatched.
2026 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2027 details.set_touch_points(2);
2028 GestureEventForTest end_second_touch_point(details, 15, 15);
2029 widget->OnGestureEvent(&end_second_touch_point);
2030 EXPECT_FALSE(end_second_touch_point.handled());
2031 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2032
2033 // If no gesture handler is set, dispatching only a ui::ET_GESTURE_END
2034 // event corresponding to the final touch point should not set the gesture
2035 // handler. Furthermore, it should not be marked as handled because it was
2036 // not dispatched (GESTURE_END events are only dispatched in cases where
2037 // a gesture handler is already set).
2038 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2039 widget->OnGestureEvent(&end);
2040 EXPECT_FALSE(end.handled());
2041 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2042
2043 // If the gesture handler has been set by a previous gesture, then it should
2044 // remain unchanged on a ui::ET_GESTURE_BEGIN or a ui::ET_GESTURE_END
2045 // corresponding to a second touch point. It should be reset to NULL by a
2046 // ui::ET_GESTURE_END corresponding to the final touch point.
2047 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2048 widget->OnGestureEvent(&tap);
2049 EXPECT_TRUE(tap.handled());
2050 EXPECT_EQ(view, GetGestureHandler(root_view));
2051
2052 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2053 widget->OnGestureEvent(&begin);
2054 EXPECT_FALSE(begin.handled());
2055 EXPECT_EQ(view, GetGestureHandler(root_view));
2056
2057 end_second_touch_point = GestureEventForTest(details, 15, 15);
2058 widget->OnGestureEvent(&end_second_touch_point);
2059 EXPECT_FALSE(end_second_touch_point.handled());
2060 EXPECT_EQ(view, GetGestureHandler(root_view));
2061
2062 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2063 widget->OnGestureEvent(&end);
2064 EXPECT_TRUE(end.handled());
2065 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2066
2067 // If the gesture handler has been set by a previous gesture, then
2068 // it should remain unchanged on a ui::ET_GESTURE_BEGIN or a
2069 // ui::ET_GESTURE_END corresponding to a second touch point and be reset
2070 // to NULL by a ui::ET_GESTURE_END corresponding to the final touch point,
2071 // even when the gesture handler has indicated that it would not like to
2072 // handle any further events.
2073 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2074 widget->OnGestureEvent(&tap);
2075 EXPECT_TRUE(tap.handled());
2076 EXPECT_EQ(view, GetGestureHandler(root_view));
2077
2078 // Change the handle mode of |view| to indicate that it does not want
2079 // to handle any further events.
2080 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2081
2082 begin = GestureEventForTest(ui::ET_GESTURE_BEGIN, 15, 15);
2083 widget->OnGestureEvent(&begin);
2084 EXPECT_FALSE(begin.handled());
2085 EXPECT_EQ(view, GetGestureHandler(root_view));
2086
2087 end_second_touch_point = GestureEventForTest(details, 15, 15);
2088 widget->OnGestureEvent(&end_second_touch_point);
2089 EXPECT_FALSE(end_second_touch_point.handled());
2090 EXPECT_EQ(view, GetGestureHandler(root_view));
2091
2092 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2093 widget->OnGestureEvent(&end);
2094 EXPECT_FALSE(end.handled());
2095 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2096
2097 widget->Close();
2098 }
2099
2100 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2101 // in a view hierarchy and that the default gesture handler in RootView is set
2102 // correctly.
TEST_F(WidgetTest,GestureEventDispatch)2103 TEST_F(WidgetTest, GestureEventDispatch) {
2104 Widget* widget = CreateTopLevelNativeWidget();
2105 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2106
2107 // Define a hierarchy of four views (coordinates are in
2108 // their parent coordinate space).
2109 // v1 (0, 0, 300, 300)
2110 // v2 (0, 0, 100, 100)
2111 // v3 (0, 0, 50, 50)
2112 // v4(0, 0, 10, 10)
2113 EventCountView* v1 = new EventCountView();
2114 v1->SetBounds(0, 0, 300, 300);
2115 EventCountView* v2 = new EventCountView();
2116 v2->SetBounds(0, 0, 100, 100);
2117 EventCountView* v3 = new EventCountView();
2118 v3->SetBounds(0, 0, 50, 50);
2119 EventCountView* v4 = new EventCountView();
2120 v4->SetBounds(0, 0, 10, 10);
2121 internal::RootView* root_view =
2122 static_cast<internal::RootView*>(widget->GetRootView());
2123 root_view->AddChildView(v1);
2124 v1->AddChildView(v2);
2125 v2->AddChildView(v3);
2126 v3->AddChildView(v4);
2127
2128 widget->Show();
2129
2130 // No gesture handler is set in the root view and none of the views in the
2131 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2132 // event should be dispatched to all views in the hierarchy, the gesture
2133 // handler should remain unset, and the event should remain unhandled.
2134 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2135 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2136 widget->OnGestureEvent(&tap);
2137 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2138 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2139 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2140 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2141 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2142 EXPECT_FALSE(tap.handled());
2143
2144 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2145 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2146 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2147 // and the event should be marked as handled.
2148 v1->ResetCounts();
2149 v2->ResetCounts();
2150 v3->ResetCounts();
2151 v4->ResetCounts();
2152 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2153 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2154 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2155 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2156 widget->OnGestureEvent(&tap);
2157 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2158 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2159 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2160 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2161 EXPECT_EQ(v3, GetGestureHandler(root_view));
2162 EXPECT_TRUE(tap.handled());
2163
2164 // The gesture handler is set to |v3| and all views handle all gesture event
2165 // types. In this case subsequent gesture events should only be dispatched to
2166 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2167 v1->ResetCounts();
2168 v2->ResetCounts();
2169 v3->ResetCounts();
2170 v4->ResetCounts();
2171 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2172 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2173 widget->OnGestureEvent(&tap);
2174 EXPECT_TRUE(tap.handled());
2175 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2176 widget->OnGestureEvent(&show_press);
2177 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2178 widget->OnGestureEvent(&tap);
2179 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2180 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2181 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2182 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2183 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2184 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2185 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2186 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2187 EXPECT_TRUE(tap.handled());
2188 EXPECT_TRUE(show_press.handled());
2189 EXPECT_EQ(v3, GetGestureHandler(root_view));
2190
2191 // The gesture handler is set to |v3|, but |v3| does not handle
2192 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2193 // only to |v3|, but the event should remain unhandled. The gesture handler
2194 // should remain as |v3|.
2195 v1->ResetCounts();
2196 v2->ResetCounts();
2197 v3->ResetCounts();
2198 v4->ResetCounts();
2199 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2200 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2201 widget->OnGestureEvent(&tap);
2202 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2203 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2204 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2205 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2206 EXPECT_FALSE(tap.handled());
2207 EXPECT_EQ(v3, GetGestureHandler(root_view));
2208
2209 widget->Close();
2210 }
2211
2212 // Tests that gesture scroll events will change the default gesture handler in
2213 // RootView if the current handler to which they are dispatched does not handle
2214 // gesture scroll events.
TEST_F(WidgetTest,ScrollGestureEventDispatch)2215 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2216 Widget* widget = CreateTopLevelNativeWidget();
2217 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2218
2219 // Define a hierarchy of four views (coordinates are in
2220 // their parent coordinate space).
2221 // v1 (0, 0, 300, 300)
2222 // v2 (0, 0, 100, 100)
2223 // v3 (0, 0, 50, 50)
2224 // v4(0, 0, 10, 10)
2225 EventCountView* v1 = new EventCountView();
2226 v1->SetBounds(0, 0, 300, 300);
2227 EventCountView* v2 = new EventCountView();
2228 v2->SetBounds(0, 0, 100, 100);
2229 EventCountView* v3 = new EventCountView();
2230 v3->SetBounds(0, 0, 50, 50);
2231 EventCountView* v4 = new EventCountView();
2232 v4->SetBounds(0, 0, 10, 10);
2233 internal::RootView* root_view =
2234 static_cast<internal::RootView*>(widget->GetRootView());
2235 root_view->AddChildView(v1);
2236 v1->AddChildView(v2);
2237 v2->AddChildView(v3);
2238 v3->AddChildView(v4);
2239
2240 widget->Show();
2241
2242 // Change the handle mode of |v3| to indicate that it would like to handle
2243 // gesture events.
2244 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2245
2246 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2247 // should bubble up the views hierarchy until it reaches the first view
2248 // that will handle it (|v3|) and then sets the handler to |v3|.
2249 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2250 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2251 widget->OnGestureEvent(&tap_down);
2252 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2253 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2254 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2255 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2256 EXPECT_EQ(v3, GetGestureHandler(root_view));
2257 EXPECT_TRUE(tap_down.handled());
2258 v1->ResetCounts();
2259 v2->ResetCounts();
2260 v3->ResetCounts();
2261 v4->ResetCounts();
2262
2263 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2264 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2265 widget->OnGestureEvent(&tap_cancel);
2266 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2267 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2268 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2269 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2270 EXPECT_EQ(v3, GetGestureHandler(root_view));
2271 EXPECT_TRUE(tap_cancel.handled());
2272 v1->ResetCounts();
2273 v2->ResetCounts();
2274 v3->ResetCounts();
2275 v4->ResetCounts();
2276
2277 // Change the handle mode of |v3| to indicate that it would no longer like
2278 // to handle events, and change the mode of |v1| to indicate that it would
2279 // like to handle events.
2280 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2281 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2282
2283 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2284 // handler (|v3|) does not handle scroll events, the event should bubble up
2285 // the views hierarchy until it reaches the first view that will handle
2286 // it (|v1|) and then sets the handler to |v1|.
2287 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2288 widget->OnGestureEvent(&scroll_begin);
2289 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2290 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2291 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2292 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2293 EXPECT_EQ(v1, GetGestureHandler(root_view));
2294 EXPECT_TRUE(scroll_begin.handled());
2295 v1->ResetCounts();
2296 v2->ResetCounts();
2297 v3->ResetCounts();
2298 v4->ResetCounts();
2299
2300 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2301 // directly.
2302 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2303 widget->OnGestureEvent(&scroll_update);
2304 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2305 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2306 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2307 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2308 EXPECT_EQ(v1, GetGestureHandler(root_view));
2309 EXPECT_TRUE(scroll_update.handled());
2310 v1->ResetCounts();
2311 v2->ResetCounts();
2312 v3->ResetCounts();
2313 v4->ResetCounts();
2314
2315 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2316 // directly and should not reset the gesture handler.
2317 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2318 widget->OnGestureEvent(&scroll_end);
2319 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2320 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2321 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2322 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2323 EXPECT_EQ(v1, GetGestureHandler(root_view));
2324 EXPECT_TRUE(scroll_end.handled());
2325 v1->ResetCounts();
2326 v2->ResetCounts();
2327 v3->ResetCounts();
2328 v4->ResetCounts();
2329
2330 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2331 // still be dispatched to |v1| directly.
2332 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2333 widget->OnGestureEvent(&pinch_begin);
2334 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2335 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2336 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2337 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2338 EXPECT_EQ(v1, GetGestureHandler(root_view));
2339 EXPECT_TRUE(pinch_begin.handled());
2340 v1->ResetCounts();
2341 v2->ResetCounts();
2342 v3->ResetCounts();
2343 v4->ResetCounts();
2344
2345 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2346 // set the gesture handler to NULL.
2347 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2348 widget->OnGestureEvent(&end);
2349 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2350 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2351 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2352 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2353 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2354 EXPECT_TRUE(end.handled());
2355
2356 widget->Close();
2357 }
2358
2359 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2360 // that when a gesture event bubbles up a View hierarchy, the location
2361 // of a gesture event seen by each View is in the local coordinate space
2362 // of that View.
2363 class GestureLocationView : public EventCountView {
2364 public:
GestureLocationView()2365 GestureLocationView() {}
~GestureLocationView()2366 virtual ~GestureLocationView() {}
2367
set_expected_location(gfx::Point expected_location)2368 void set_expected_location(gfx::Point expected_location) {
2369 expected_location_ = expected_location;
2370 }
2371
2372 // EventCountView:
OnGestureEvent(ui::GestureEvent * event)2373 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
2374 EventCountView::OnGestureEvent(event);
2375
2376 // Verify that the location of |event| is in the local coordinate
2377 // space of |this|.
2378 EXPECT_EQ(expected_location_, event->location());
2379 }
2380
2381 private:
2382 // The expected location of a gesture event dispatched to |this|.
2383 gfx::Point expected_location_;
2384
2385 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2386 };
2387
2388 // Verifies that the location of a gesture event is always in the local
2389 // coordinate space of the View receiving the event while bubbling.
TEST_F(WidgetTest,GestureEventLocationWhileBubbling)2390 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2391 Widget* widget = CreateTopLevelNativeWidget();
2392 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2393
2394 // Define a hierarchy of three views (coordinates shown below are in the
2395 // coordinate space of the root view, but the coordinates used for
2396 // SetBounds() are in their parent coordinate space).
2397 // v1 (50, 50, 150, 150)
2398 // v2 (100, 70, 50, 80)
2399 // v3 (120, 100, 10, 10)
2400 GestureLocationView* v1 = new GestureLocationView();
2401 v1->SetBounds(50, 50, 150, 150);
2402 GestureLocationView* v2 = new GestureLocationView();
2403 v2->SetBounds(50, 20, 50, 80);
2404 GestureLocationView* v3 = new GestureLocationView();
2405 v3->SetBounds(20, 30, 10, 10);
2406 internal::RootView* root_view =
2407 static_cast<internal::RootView*>(widget->GetRootView());
2408 root_view->AddChildView(v1);
2409 v1->AddChildView(v2);
2410 v2->AddChildView(v3);
2411
2412 widget->Show();
2413
2414 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2415 // This event is contained within all of |v1|, |v2|, and |v3|.
2416 gfx::Point location_in_root(125, 105);
2417 GestureEventForTest tap(
2418 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2419
2420 // Calculate the location of the event in the local coordinate spaces
2421 // of each of the views.
2422 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2423 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2424 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2425 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2426 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2427 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2428
2429 // Dispatch the event. When each view receives the event, its location should
2430 // be in the local coordinate space of that view (see the check made by
2431 // GestureLocationView). After dispatch is complete the event's location
2432 // should be in the root coordinate space.
2433 v1->set_expected_location(location_in_v1);
2434 v2->set_expected_location(location_in_v2);
2435 v3->set_expected_location(location_in_v3);
2436 widget->OnGestureEvent(&tap);
2437 EXPECT_EQ(location_in_root, tap.location());
2438
2439 // Verify that each view did in fact see the event.
2440 EventCountView* view1 = v1;
2441 EventCountView* view2 = v2;
2442 EventCountView* view3 = v3;
2443 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2444 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2445 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2446
2447 widget->Close();
2448 }
2449
2450 // Verifies that disabled views are permitted to be set as the default gesture
2451 // handler in RootView. Also verifies that gesture events targeted to a disabled
2452 // view are not actually dispatched to the view, but are still marked as
2453 // handled.
TEST_F(WidgetTest,DisabledGestureEventTarget)2454 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2455 Widget* widget = CreateTopLevelNativeWidget();
2456 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2457
2458 // Define a hierarchy of four views (coordinates are in
2459 // their parent coordinate space).
2460 // v1 (0, 0, 300, 300)
2461 // v2 (0, 0, 100, 100)
2462 // v3 (0, 0, 50, 50)
2463 // v4(0, 0, 10, 10)
2464 EventCountView* v1 = new EventCountView();
2465 v1->SetBounds(0, 0, 300, 300);
2466 EventCountView* v2 = new EventCountView();
2467 v2->SetBounds(0, 0, 100, 100);
2468 EventCountView* v3 = new EventCountView();
2469 v3->SetBounds(0, 0, 50, 50);
2470 EventCountView* v4 = new EventCountView();
2471 v4->SetBounds(0, 0, 10, 10);
2472 internal::RootView* root_view =
2473 static_cast<internal::RootView*>(widget->GetRootView());
2474 root_view->AddChildView(v1);
2475 v1->AddChildView(v2);
2476 v2->AddChildView(v3);
2477 v3->AddChildView(v4);
2478
2479 widget->Show();
2480
2481 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2482 // disabled.
2483 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2484 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2485 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2486 v3->SetEnabled(false);
2487
2488 // No gesture handler is set in the root view, so it should remain unset
2489 // after a GESTURE_END. GESTURE_END events are not dispatched unless
2490 // a gesture handler is already set in the root view, so none of the
2491 // views should see this event and it should not be marked as handled.
2492 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2493 widget->OnGestureEvent(&end);
2494 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2495 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2496 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2497 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2498 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2499 EXPECT_FALSE(end.handled());
2500 v1->ResetCounts();
2501 v2->ResetCounts();
2502 v3->ResetCounts();
2503 v4->ResetCounts();
2504
2505 // No gesture handler is set in the root view. In this case the tap event
2506 // should be dispatched only to |v4|, the gesture handler should be set to
2507 // |v3|, and the event should be marked as handled.
2508 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2509 widget->OnGestureEvent(&tap);
2510 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2511 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2512 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2513 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2514 EXPECT_EQ(v3, GetGestureHandler(root_view));
2515 EXPECT_TRUE(tap.handled());
2516 v1->ResetCounts();
2517 v2->ResetCounts();
2518 v3->ResetCounts();
2519 v4->ResetCounts();
2520
2521 // A subsequent gesture event should be marked as handled but not dispatched.
2522 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2523 widget->OnGestureEvent(&tap);
2524 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2525 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2526 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2527 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2528 EXPECT_EQ(v3, GetGestureHandler(root_view));
2529 EXPECT_TRUE(tap.handled());
2530 v1->ResetCounts();
2531 v2->ResetCounts();
2532 v3->ResetCounts();
2533 v4->ResetCounts();
2534
2535 // A GESTURE_END should reset the default gesture handler to NULL. It should
2536 // also not be dispatched to |v3| but still marked as handled.
2537 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2538 widget->OnGestureEvent(&end);
2539 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2540 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2541 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2542 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2543 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2544 EXPECT_TRUE(end.handled());
2545 v1->ResetCounts();
2546 v2->ResetCounts();
2547 v3->ResetCounts();
2548 v4->ResetCounts();
2549
2550 // Change the handle mode of |v3| to indicate that it would no longer like
2551 // to handle events which are dispatched to it.
2552 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2553
2554 // No gesture handler is set in the root view. In this case the tap event
2555 // should be dispatched only to |v4| and the event should be marked as
2556 // handled. Furthermore, the gesture handler should be set to
2557 // |v3|; even though |v3| does not explicitly handle events, it is a
2558 // valid target for the tap event because it is disabled.
2559 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2560 widget->OnGestureEvent(&tap);
2561 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2562 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2563 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2564 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2565 EXPECT_EQ(v3, GetGestureHandler(root_view));
2566 EXPECT_TRUE(tap.handled());
2567 v1->ResetCounts();
2568 v2->ResetCounts();
2569 v3->ResetCounts();
2570 v4->ResetCounts();
2571
2572 // A GESTURE_END should reset the default gesture handler to NULL. It should
2573 // also not be dispatched to |v3| but still marked as handled.
2574 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2575 widget->OnGestureEvent(&end);
2576 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2577 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2578 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2579 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2580 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2581 EXPECT_TRUE(end.handled());
2582
2583 widget->Close();
2584 }
2585
2586 // Test the result of Widget::GetAllChildWidgets().
TEST_F(WidgetTest,GetAllChildWidgets)2587 TEST_F(WidgetTest, GetAllChildWidgets) {
2588 // Create the following widget hierarchy:
2589 //
2590 // toplevel
2591 // +-- w1
2592 // +-- w11
2593 // +-- w2
2594 // +-- w21
2595 // +-- w22
2596 Widget* toplevel = CreateTopLevelPlatformWidget();
2597 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2598 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2599 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2600 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2601 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2602
2603 std::set<Widget*> expected;
2604 expected.insert(toplevel);
2605 expected.insert(w1);
2606 expected.insert(w11);
2607 expected.insert(w2);
2608 expected.insert(w21);
2609 expected.insert(w22);
2610
2611 std::set<Widget*> widgets;
2612 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2613
2614 EXPECT_EQ(expected.size(), widgets.size());
2615 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2616 }
2617
2618 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2619 // a vector.
2620 class DestroyedTrackingView : public View {
2621 public:
DestroyedTrackingView(const std::string & name,std::vector<std::string> * add_to)2622 DestroyedTrackingView(const std::string& name,
2623 std::vector<std::string>* add_to)
2624 : name_(name),
2625 add_to_(add_to) {
2626 }
2627
~DestroyedTrackingView()2628 virtual ~DestroyedTrackingView() {
2629 add_to_->push_back(name_);
2630 }
2631
2632 private:
2633 const std::string name_;
2634 std::vector<std::string>* add_to_;
2635
2636 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2637 };
2638
2639 class WidgetChildDestructionTest : public WidgetTest {
2640 public:
WidgetChildDestructionTest()2641 WidgetChildDestructionTest() {}
2642
2643 // Creates a top level and a child, destroys the child and verifies the views
2644 // of the child are destroyed before the views of the parent.
RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,bool child_has_desktop_native_widget_aura)2645 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2646 bool child_has_desktop_native_widget_aura) {
2647 // When a View is destroyed its name is added here.
2648 std::vector<std::string> destroyed;
2649
2650 Widget* top_level = new Widget;
2651 Widget::InitParams params =
2652 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2653 #if !defined(OS_CHROMEOS)
2654 if (top_level_has_desktop_native_widget_aura)
2655 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2656 #endif
2657 top_level->Init(params);
2658 top_level->GetRootView()->AddChildView(
2659 new DestroyedTrackingView("parent", &destroyed));
2660 top_level->Show();
2661
2662 Widget* child = new Widget;
2663 Widget::InitParams child_params =
2664 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2665 child_params.parent = top_level->GetNativeView();
2666 #if !defined(OS_CHROMEOS)
2667 if (child_has_desktop_native_widget_aura)
2668 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2669 #endif
2670 child->Init(child_params);
2671 child->GetRootView()->AddChildView(
2672 new DestroyedTrackingView("child", &destroyed));
2673 child->Show();
2674
2675 // Should trigger destruction of the child too.
2676 top_level->native_widget_private()->CloseNow();
2677
2678 // Child should be destroyed first.
2679 ASSERT_EQ(2u, destroyed.size());
2680 EXPECT_EQ("child", destroyed[0]);
2681 EXPECT_EQ("parent", destroyed[1]);
2682 }
2683
2684 private:
2685 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2686 };
2687
2688 #if !defined(OS_CHROMEOS)
2689 // See description of RunDestroyChildWidgetsTest(). Parent uses
2690 // DesktopNativeWidgetAura.
TEST_F(WidgetChildDestructionTest,DestroyChildWidgetsInOrderWithDesktopNativeWidget)2691 TEST_F(WidgetChildDestructionTest,
2692 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2693 RunDestroyChildWidgetsTest(true, false);
2694 }
2695
2696 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2697 // DesktopNativeWidgetAura.
TEST_F(WidgetChildDestructionTest,DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth)2698 TEST_F(WidgetChildDestructionTest,
2699 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2700 RunDestroyChildWidgetsTest(true, true);
2701 }
2702 #endif // !defined(OS_CHROMEOS)
2703
2704 // See description of RunDestroyChildWidgetsTest().
TEST_F(WidgetChildDestructionTest,DestroyChildWidgetsInOrder)2705 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2706 RunDestroyChildWidgetsTest(false, false);
2707 }
2708
2709 #if !defined(OS_CHROMEOS)
2710 // Provides functionality to create a window modal dialog.
2711 class ModalDialogDelegate : public DialogDelegateView {
2712 public:
ModalDialogDelegate()2713 ModalDialogDelegate() {}
~ModalDialogDelegate()2714 virtual ~ModalDialogDelegate() {}
2715
2716 // WidgetDelegate overrides.
GetModalType() const2717 virtual ui::ModalType GetModalType() const OVERRIDE {
2718 return ui::MODAL_TYPE_WINDOW;
2719 }
2720
2721 private:
2722 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2723 };
2724
2725 // This test verifies that whether mouse events when a modal dialog is
2726 // displayed are eaten or recieved by the dialog.
TEST_F(WidgetTest,WindowMouseModalityTest)2727 TEST_F(WidgetTest, WindowMouseModalityTest) {
2728 // Create a top level widget.
2729 Widget top_level_widget;
2730 Widget::InitParams init_params =
2731 CreateParams(Widget::InitParams::TYPE_WINDOW);
2732 init_params.show_state = ui::SHOW_STATE_NORMAL;
2733 gfx::Rect initial_bounds(0, 0, 500, 500);
2734 init_params.bounds = initial_bounds;
2735 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2736 init_params.native_widget =
2737 new PlatformDesktopNativeWidget(&top_level_widget);
2738 top_level_widget.Init(init_params);
2739 top_level_widget.Show();
2740 EXPECT_TRUE(top_level_widget.IsVisible());
2741
2742 // Create a view and validate that a mouse moves makes it to the view.
2743 EventCountView* widget_view = new EventCountView();
2744 widget_view->SetBounds(0, 0, 10, 10);
2745 top_level_widget.GetRootView()->AddChildView(widget_view);
2746
2747 gfx::Point cursor_location_main(5, 5);
2748 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2749 cursor_location_main,
2750 cursor_location_main,
2751 ui::EF_NONE,
2752 ui::EF_NONE);
2753 ui::EventDispatchDetails details =
2754 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2755 ASSERT_FALSE(details.dispatcher_destroyed);
2756
2757 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2758 widget_view->ResetCounts();
2759
2760 // Create a modal dialog and validate that a mouse down message makes it to
2761 // the main view within the dialog.
2762
2763 // This instance will be destroyed when the dialog is destroyed.
2764 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2765
2766 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2767 dialog_delegate, NULL, top_level_widget.GetNativeView());
2768 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2769 EventCountView* dialog_widget_view = new EventCountView();
2770 dialog_widget_view->SetBounds(0, 0, 50, 50);
2771 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2772 modal_dialog_widget->Show();
2773 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2774
2775 gfx::Point cursor_location_dialog(100, 100);
2776 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2777 cursor_location_dialog,
2778 cursor_location_dialog,
2779 ui::EF_NONE,
2780 ui::EF_NONE);
2781 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2782 &mouse_down_dialog);
2783 ASSERT_FALSE(details.dispatcher_destroyed);
2784 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2785
2786 // Send a mouse move message to the main window. It should not be received by
2787 // the main window as the modal dialog is still active.
2788 gfx::Point cursor_location_main2(6, 6);
2789 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2790 cursor_location_main2,
2791 cursor_location_main2,
2792 ui::EF_NONE,
2793 ui::EF_NONE);
2794 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2795 &mouse_down_main);
2796 ASSERT_FALSE(details.dispatcher_destroyed);
2797 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2798
2799 modal_dialog_widget->CloseNow();
2800 top_level_widget.CloseNow();
2801 }
2802
2803 // Verifies nativeview visbility matches that of Widget visibility when
2804 // SetFullscreen is invoked.
TEST_F(WidgetTest,FullscreenStatePropagated)2805 TEST_F(WidgetTest, FullscreenStatePropagated) {
2806 Widget::InitParams init_params =
2807 CreateParams(Widget::InitParams::TYPE_WINDOW);
2808 init_params.show_state = ui::SHOW_STATE_NORMAL;
2809 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2810 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2811
2812 {
2813 Widget top_level_widget;
2814 top_level_widget.Init(init_params);
2815 top_level_widget.SetFullscreen(true);
2816 EXPECT_EQ(top_level_widget.IsVisible(),
2817 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2818 top_level_widget.CloseNow();
2819 }
2820 #if !defined(OS_CHROMEOS)
2821 {
2822 Widget top_level_widget;
2823 init_params.native_widget =
2824 new PlatformDesktopNativeWidget(&top_level_widget);
2825 top_level_widget.Init(init_params);
2826 top_level_widget.SetFullscreen(true);
2827 EXPECT_EQ(top_level_widget.IsVisible(),
2828 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2829 top_level_widget.CloseNow();
2830 }
2831 #endif
2832 }
2833 #if defined(OS_WIN)
2834
2835 // Provides functionality to test widget activation via an activation flag
2836 // which can be set by an accessor.
2837 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2838 public:
ModalWindowTestWidgetDelegate()2839 ModalWindowTestWidgetDelegate()
2840 : widget_(NULL),
2841 can_activate_(true) {}
2842
~ModalWindowTestWidgetDelegate()2843 virtual ~ModalWindowTestWidgetDelegate() {}
2844
2845 // Overridden from WidgetDelegate:
DeleteDelegate()2846 virtual void DeleteDelegate() OVERRIDE {
2847 delete this;
2848 }
GetWidget()2849 virtual Widget* GetWidget() OVERRIDE {
2850 return widget_;
2851 }
GetWidget() const2852 virtual const Widget* GetWidget() const OVERRIDE {
2853 return widget_;
2854 }
CanActivate() const2855 virtual bool CanActivate() const OVERRIDE {
2856 return can_activate_;
2857 }
ShouldAdvanceFocusToTopLevelWidget() const2858 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
2859 return true;
2860 }
2861
set_can_activate(bool can_activate)2862 void set_can_activate(bool can_activate) {
2863 can_activate_ = can_activate;
2864 }
2865
set_widget(Widget * widget)2866 void set_widget(Widget* widget) {
2867 widget_ = widget;
2868 }
2869
2870 private:
2871 Widget* widget_;
2872 bool can_activate_;
2873
2874 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2875 };
2876
2877 // Tests whether we can activate the top level widget when a modal dialog is
2878 // active.
TEST_F(WidgetTest,WindowModalityActivationTest)2879 TEST_F(WidgetTest, WindowModalityActivationTest) {
2880 // Destroyed when the top level widget created below is destroyed.
2881 ModalWindowTestWidgetDelegate* widget_delegate =
2882 new ModalWindowTestWidgetDelegate;
2883 // Create a top level widget.
2884 Widget top_level_widget;
2885 Widget::InitParams init_params =
2886 CreateParams(Widget::InitParams::TYPE_WINDOW);
2887 init_params.show_state = ui::SHOW_STATE_NORMAL;
2888 gfx::Rect initial_bounds(0, 0, 500, 500);
2889 init_params.bounds = initial_bounds;
2890 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2891 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2892 init_params.delegate = widget_delegate;
2893 top_level_widget.Init(init_params);
2894 widget_delegate->set_widget(&top_level_widget);
2895 top_level_widget.Show();
2896 EXPECT_TRUE(top_level_widget.IsVisible());
2897
2898 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2899 EXPECT_TRUE(::IsWindow(win32_window));
2900
2901 // This instance will be destroyed when the dialog is destroyed.
2902 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2903
2904 // We should be able to activate the window even if the WidgetDelegate
2905 // says no, when a modal dialog is active.
2906 widget_delegate->set_can_activate(false);
2907
2908 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2909 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2910 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2911 modal_dialog_widget->Show();
2912 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2913
2914 LRESULT activate_result = ::SendMessage(
2915 win32_window,
2916 WM_MOUSEACTIVATE,
2917 reinterpret_cast<WPARAM>(win32_window),
2918 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
2919 EXPECT_EQ(activate_result, MA_ACTIVATE);
2920
2921 modal_dialog_widget->CloseNow();
2922 top_level_widget.CloseNow();
2923 }
2924 #endif // defined(OS_WIN)
2925 #endif // !defined(OS_CHROMEOS)
2926
TEST_F(WidgetTest,ShowCreatesActiveWindow)2927 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
2928 Widget* widget = CreateTopLevelPlatformWidget();
2929
2930 widget->Show();
2931 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2932
2933 widget->CloseNow();
2934 }
2935
2936 // OSX does not have a per-application "active" window such as provided by
2937 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
2938 // is updated asynchronously.
2939 #if defined(OS_MACOSX)
2940 #define MAYBE_ShowInactive DISABLED_ShowInactive
2941 #else
2942 #define MAYBE_ShowInactive ShowInactive
2943 #endif
TEST_F(WidgetTest,MAYBE_ShowInactive)2944 TEST_F(WidgetTest, MAYBE_ShowInactive) {
2945 Widget* widget = CreateTopLevelPlatformWidget();
2946
2947 widget->ShowInactive();
2948 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
2949
2950 widget->CloseNow();
2951 }
2952
TEST_F(WidgetTest,InactiveBeforeShow)2953 TEST_F(WidgetTest, InactiveBeforeShow) {
2954 Widget* widget = CreateTopLevelPlatformWidget();
2955
2956 EXPECT_FALSE(widget->IsActive());
2957 EXPECT_FALSE(widget->IsVisible());
2958
2959 widget->Show();
2960
2961 EXPECT_TRUE(widget->IsActive());
2962 EXPECT_TRUE(widget->IsVisible());
2963
2964 widget->CloseNow();
2965 }
2966
TEST_F(WidgetTest,ShowInactiveAfterShow)2967 TEST_F(WidgetTest, ShowInactiveAfterShow) {
2968 // Create 2 widgets to ensure window layering does not change.
2969 Widget* widget = CreateTopLevelPlatformWidget();
2970 Widget* widget2 = CreateTopLevelPlatformWidget();
2971
2972 widget2->Show();
2973 EXPECT_FALSE(widget->IsActive());
2974 EXPECT_TRUE(widget2->IsVisible());
2975 EXPECT_TRUE(widget2->IsActive());
2976
2977 widget->Show();
2978 EXPECT_TRUE(widget->IsActive());
2979 EXPECT_FALSE(widget2->IsActive());
2980 widget->ShowInactive();
2981 EXPECT_TRUE(widget->IsActive());
2982 EXPECT_FALSE(widget2->IsActive());
2983 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2984
2985 widget2->CloseNow();
2986 widget->CloseNow();
2987 }
2988
TEST_F(WidgetTest,ShowAfterShowInactive)2989 TEST_F(WidgetTest, ShowAfterShowInactive) {
2990 Widget* widget = CreateTopLevelPlatformWidget();
2991
2992 widget->ShowInactive();
2993 widget->Show();
2994 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
2995
2996 widget->CloseNow();
2997 }
2998
2999 #if !defined(OS_CHROMEOS)
TEST_F(WidgetTest,InactiveWidgetDoesNotGrabActivation)3000 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
3001 Widget* widget = CreateTopLevelPlatformWidget();
3002 widget->Show();
3003 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3004
3005 Widget widget2;
3006 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3007 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
3008 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3009 widget2.Init(params);
3010 widget2.Show();
3011
3012 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
3013 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3014
3015 widget->CloseNow();
3016 widget2.CloseNow();
3017 }
3018 #endif // !defined(OS_CHROMEOS)
3019
3020 namespace {
3021
3022 class FullscreenAwareFrame : public views::NonClientFrameView {
3023 public:
FullscreenAwareFrame(views::Widget * widget)3024 explicit FullscreenAwareFrame(views::Widget* widget)
3025 : widget_(widget), fullscreen_layout_called_(false) {}
~FullscreenAwareFrame()3026 virtual ~FullscreenAwareFrame() {}
3027
3028 // views::NonClientFrameView overrides:
GetBoundsForClientView() const3029 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
3030 return gfx::Rect();
3031 }
GetWindowBoundsForClientBounds(const gfx::Rect & client_bounds) const3032 virtual gfx::Rect GetWindowBoundsForClientBounds(
3033 const gfx::Rect& client_bounds) const OVERRIDE {
3034 return gfx::Rect();
3035 }
NonClientHitTest(const gfx::Point & point)3036 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
3037 return HTNOWHERE;
3038 }
GetWindowMask(const gfx::Size & size,gfx::Path * window_mask)3039 virtual void GetWindowMask(const gfx::Size& size,
3040 gfx::Path* window_mask) OVERRIDE {}
ResetWindowControls()3041 virtual void ResetWindowControls() OVERRIDE {}
UpdateWindowIcon()3042 virtual void UpdateWindowIcon() OVERRIDE {}
UpdateWindowTitle()3043 virtual void UpdateWindowTitle() OVERRIDE {}
SizeConstraintsChanged()3044 virtual void SizeConstraintsChanged() OVERRIDE {}
3045
3046 // views::View overrides:
Layout()3047 virtual void Layout() OVERRIDE {
3048 if (widget_->IsFullscreen())
3049 fullscreen_layout_called_ = true;
3050 }
3051
fullscreen_layout_called() const3052 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3053
3054 private:
3055 views::Widget* widget_;
3056 bool fullscreen_layout_called_;
3057
3058 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3059 };
3060
3061 } // namespace
3062
3063 // Tests that frame Layout is called when a widget goes fullscreen without
3064 // changing its size or title.
TEST_F(WidgetTest,FullscreenFrameLayout)3065 TEST_F(WidgetTest, FullscreenFrameLayout) {
3066 Widget* widget = CreateTopLevelPlatformWidget();
3067 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3068 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3069
3070 widget->Maximize();
3071 RunPendingMessages();
3072
3073 EXPECT_FALSE(frame->fullscreen_layout_called());
3074 widget->SetFullscreen(true);
3075 widget->Show();
3076 RunPendingMessages();
3077 EXPECT_TRUE(frame->fullscreen_layout_called());
3078
3079 widget->CloseNow();
3080 }
3081
3082 #if !defined(OS_CHROMEOS)
3083 namespace {
3084
3085 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3086 // OnWindowDestroying.
3087 class IsActiveFromDestroyObserver : public WidgetObserver {
3088 public:
IsActiveFromDestroyObserver()3089 IsActiveFromDestroyObserver() {}
~IsActiveFromDestroyObserver()3090 virtual ~IsActiveFromDestroyObserver() {}
OnWidgetDestroying(Widget * widget)3091 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
3092 widget->IsActive();
3093 }
3094
3095 private:
3096 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3097 };
3098
3099 } // namespace
3100
3101 // Verifies Widget::IsActive() invoked from
3102 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
TEST_F(WidgetTest,IsActiveFromDestroy)3103 TEST_F(WidgetTest, IsActiveFromDestroy) {
3104 // Create two widgets, one a child of the other.
3105 IsActiveFromDestroyObserver observer;
3106 Widget parent_widget;
3107 Widget::InitParams parent_params =
3108 CreateParams(Widget::InitParams::TYPE_POPUP);
3109 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3110 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3111 parent_widget.Init(parent_params);
3112 parent_widget.Show();
3113
3114 Widget child_widget;
3115 Widget::InitParams child_params =
3116 CreateParams(Widget::InitParams::TYPE_POPUP);
3117 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3118 child_params.context = parent_widget.GetNativeWindow();
3119 child_widget.Init(child_params);
3120 child_widget.AddObserver(&observer);
3121 child_widget.Show();
3122
3123 parent_widget.CloseNow();
3124 }
3125 #endif // !defined(OS_CHROMEOS)
3126
3127 // Tests that events propagate through from the dispatcher with the correct
3128 // event type, and that the different platforms behave the same.
TEST_F(WidgetTest,MouseEventTypesViaGenerator)3129 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3130 EventCountView* view = new EventCountView;
3131 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3132 view->SetBounds(10, 10, 50, 40);
3133
3134 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3135 widget->GetRootView()->AddChildView(view);
3136
3137 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3138 widget->Show();
3139
3140 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3141 generator.set_current_location(gfx::Point(20, 20));
3142
3143 generator.ClickLeftButton();
3144 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3145 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3146 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3147
3148 generator.PressRightButton();
3149 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3150 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3151 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3152
3153 generator.ReleaseRightButton();
3154 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3155 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3156 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3157
3158 // Test mouse move events.
3159 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3160 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3161
3162 // Move the mouse within the view (20, 20) -> (30, 30).
3163 generator.MoveMouseTo(gfx::Point(30, 30));
3164 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3165 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3166 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3167
3168 // Move it again - entered count shouldn't change.
3169 generator.MoveMouseTo(gfx::Point(31, 31));
3170 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3171 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3172 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3173
3174 // Move it off the view.
3175 generator.MoveMouseTo(gfx::Point(5, 5));
3176 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3177 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3178 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3179
3180 // Move it back on.
3181 generator.MoveMouseTo(gfx::Point(20, 20));
3182 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3183 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3184 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3185
3186 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3187 generator.DragMouseTo(gfx::Point(40, 40));
3188 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3189 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3190 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3191 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3192
3193 widget->CloseNow();
3194 }
3195
3196 // Tests that the root view is correctly set up for Widget types that do not
3197 // require a non-client view, before any other views are added to the widget.
3198 // That is, before Widget::ReorderNativeViews() is called which, if called with
3199 // a root view not set, could cause the root view to get resized to the widget.
TEST_F(WidgetTest,NonClientWindowValidAfterInit)3200 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3201 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3202 View* root_view = widget->GetRootView();
3203
3204 // Size the root view to exceed the widget bounds.
3205 const gfx::Rect test_rect(0, 0, 500, 500);
3206 root_view->SetBoundsRect(test_rect);
3207
3208 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3209
3210 EXPECT_EQ(test_rect, root_view->bounds());
3211 widget->ReorderNativeViews();
3212 EXPECT_EQ(test_rect, root_view->bounds());
3213
3214 widget->CloseNow();
3215 }
3216
3217 } // namespace test
3218 } // namespace views
3219