Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: ui/views/widget/widget_unittest.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/widget/widget_removals_observer.h ('k') | ui/views/widget/window_reorderer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
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
66 EventCountView()
67 : last_flags_(0),
68 handle_mode_(PROPAGATE_EVENTS) {}
69
70 virtual ~EventCountView() {}
71
72 int GetEventCount(ui::EventType type) {
73 return event_count_[type];
74 }
75
76 void ResetCounts() {
77 event_count_.clear();
78 }
79
80 int last_flags() const {
81 return last_flags_;
82 }
83
84 void set_handle_mode(HandleMode handle_mode) {
85 handle_mode_ = handle_mode;
86 }
87
88 protected:
89 // Overridden from View:
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:
97 virtual void OnKeyEvent(ui::KeyEvent* event) override {
98 RecordEvent(event);
99 }
100 virtual void OnMouseEvent(ui::MouseEvent* event) override {
101 RecordEvent(event);
102 }
103 virtual void OnScrollEvent(ui::ScrollEvent* event) override {
104 RecordEvent(event);
105 }
106 virtual void OnGestureEvent(ui::GestureEvent* event) override {
107 RecordEvent(event);
108 }
109
110 private:
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:
129 ScrollableEventCountView() {}
130 virtual ~ScrollableEventCountView() {}
131
132 private:
133 // Overridden from ui::EventHandler:
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
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:
160 explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
161 virtual ~MinimumSizeFrameView() {}
162
163 private:
164 // Overridden from View:
165 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:
176 EventCountHandler() {}
177 virtual ~EventCountHandler() {}
178
179 int GetEventCount(ui::EventType type) {
180 return event_count_[type];
181 }
182
183 void ResetCounts() {
184 event_count_.clear();
185 }
186
187 protected:
188 // Overridden from ui::EventHandler:
189 virtual void OnEvent(ui::Event* event) override {
190 RecordEvent(*event);
191 ui::EventHandler::OnEvent(event);
192 }
193
194 private:
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:
208 explicit CloseWidgetView(ui::EventType event_type)
209 : event_type_(event_type) {
210 }
211
212 // ui::EventHandler override:
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
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
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
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.
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.
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:
323 WidgetOwnershipTest() {}
324 virtual ~WidgetOwnershipTest() {}
325
326 virtual void SetUp() {
327 WidgetTest::SetUp();
328 desktop_widget_ = CreateTopLevelPlatformWidget();
329 }
330
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 {
344 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:
354 OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
355 OwnershipTestState* state)
356 : PlatformNativeWidget(delegate),
357 state_(state) {
358 }
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:
373 OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
374 OwnershipTestState* state)
375 : NativeWidgetCapture(delegate),
376 state_(state) {
377 }
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:
391 explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
621 WidgetWithDestroyedNativeViewTest() {}
622 virtual ~WidgetWithDestroyedNativeViewTest() {}
623
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
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:
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
718 virtual ~WidgetObserverTest() {}
719
720 // Overridden from WidgetObserver:
721 virtual void OnWidgetDestroying(Widget* widget) override {
722 if (active_ == widget)
723 active_ = NULL;
724 widget_closed_ = widget;
725 }
726
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
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
749 virtual void OnWidgetBoundsChanged(Widget* widget,
750 const gfx::Rect& new_bounds) override {
751 widget_bounds_changed_ = widget;
752 }
753
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
764 Widget* NewWidget() {
765 Widget* widget = CreateTopLevelNativeWidget();
766 widget->AddObserver(this);
767 return widget;
768 }
769
770 const Widget* active() const { return active_; }
771 const Widget* widget_closed() const { return widget_closed_; }
772 const Widget* widget_activated() const { return widget_activated_; }
773 const Widget* widget_deactivated() const { return widget_deactivated_; }
774 const Widget* widget_shown() const { return widget_shown_; }
775 const Widget* widget_hidden() const { return widget_hidden_; }
776 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
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
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
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
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.
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 // Before being enabled on Mac, this was #ifdef(false).
932 // TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
933 #if defined(OS_MACOSX)
934 // Aura needs shell to maximize/fullscreen window.
935 // NativeWidgetGtk doesn't implement GetRestoredBounds.
936 TEST_F(WidgetTest, GetRestoredBounds) {
937 Widget* toplevel = CreateTopLevelPlatformWidget();
938 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
939 toplevel->GetRestoredBounds().ToString());
940 toplevel->Show();
941 toplevel->Maximize();
942 RunPendingMessages();
943 #if defined(OS_MACOSX)
944 // Current expectation on Mac is to do nothing on Maximize.
945 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
946 toplevel->GetRestoredBounds().ToString());
947 #else
948 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
949 toplevel->GetRestoredBounds().ToString());
950 #endif
951 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
952 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
953
954 toplevel->Restore();
955 RunPendingMessages();
956 EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
957 toplevel->GetRestoredBounds().ToString());
958
959 toplevel->SetFullscreen(true);
960 RunPendingMessages();
961 EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
962 toplevel->GetRestoredBounds().ToString());
963 EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
964 EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
965 }
966 #endif
967
968 // Test that window state is not changed after getting out of full screen.
969 TEST_F(WidgetTest, ExitFullscreenRestoreState) {
970 Widget* toplevel = CreateTopLevelPlatformWidget();
971
972 toplevel->Show();
973 RunPendingMessages();
974
975 // This should be a normal state window.
976 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
977
978 toplevel->SetFullscreen(true);
979 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
980 toplevel->SetFullscreen(false);
981 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
982
983 // And it should still be in normal state after getting out of full screen.
984 EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
985
986 // On Mac, a "maximized" state is indistinguishable from a window that just
987 // fills the screen, so nothing to check there.
988 #if !defined(OS_MACOSX)
989 // Now, make it maximized.
990 toplevel->Maximize();
991 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
992
993 toplevel->SetFullscreen(true);
994 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
995 toplevel->SetFullscreen(false);
996 EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
997
998 // And it stays maximized after getting out of full screen.
999 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
1000 #endif
1001
1002 // Clean up.
1003 toplevel->Close();
1004 RunPendingMessages();
1005 }
1006
1007 // The key-event propagation from Widget happens differently on aura and
1008 // non-aura systems because of the difference in IME. So this test works only on
1009 // aura.
1010 TEST_F(WidgetTest, KeyboardInputEvent) {
1011 Widget* toplevel = CreateTopLevelPlatformWidget();
1012 View* container = toplevel->client_view();
1013
1014 Textfield* textfield = new Textfield();
1015 textfield->SetText(base::ASCIIToUTF16("some text"));
1016 container->AddChildView(textfield);
1017 toplevel->Show();
1018 textfield->RequestFocus();
1019
1020 // The press gets handled. The release doesn't have an effect.
1021 ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
1022 toplevel->OnKeyEvent(&backspace_p);
1023 EXPECT_TRUE(backspace_p.stopped_propagation());
1024 ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
1025 toplevel->OnKeyEvent(&backspace_r);
1026 EXPECT_FALSE(backspace_r.handled());
1027
1028 toplevel->Close();
1029 }
1030
1031 // Verifies bubbles result in a focus lost when shown.
1032 // TODO(msw): this tests relies on focus, it needs to be in
1033 // interactive_ui_tests.
1034 TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
1035 // Create a widget, show and activate it and focus the contents view.
1036 View* contents_view = new View;
1037 contents_view->SetFocusable(true);
1038 Widget widget;
1039 Widget::InitParams init_params =
1040 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1041 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1042 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1043 #if !defined(OS_CHROMEOS)
1044 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1045 #endif
1046 widget.Init(init_params);
1047 widget.SetContentsView(contents_view);
1048 widget.Show();
1049 widget.Activate();
1050 contents_view->RequestFocus();
1051 EXPECT_TRUE(contents_view->HasFocus());
1052
1053 // Show a bubble.
1054 BubbleDelegateView* bubble_delegate_view =
1055 new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
1056 bubble_delegate_view->SetFocusable(true);
1057 BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
1058 bubble_delegate_view->RequestFocus();
1059
1060 // |contents_view_| should no longer have focus.
1061 EXPECT_FALSE(contents_view->HasFocus());
1062 EXPECT_TRUE(bubble_delegate_view->HasFocus());
1063
1064 bubble_delegate_view->GetWidget()->CloseNow();
1065
1066 // Closing the bubble should result in focus going back to the contents view.
1067 EXPECT_TRUE(contents_view->HasFocus());
1068 }
1069
1070 class TestBubbleDelegateView : public BubbleDelegateView {
1071 public:
1072 TestBubbleDelegateView(View* anchor)
1073 : BubbleDelegateView(anchor, BubbleBorder::NONE),
1074 reset_controls_called_(false) {}
1075 virtual ~TestBubbleDelegateView() {}
1076
1077 virtual bool ShouldShowCloseButton() const override {
1078 reset_controls_called_ = true;
1079 return true;
1080 }
1081
1082 mutable bool reset_controls_called_;
1083 };
1084
1085 TEST_F(WidgetTest, BubbleControlsResetOnInit) {
1086 Widget* anchor = CreateTopLevelPlatformWidget();
1087 anchor->Show();
1088
1089 TestBubbleDelegateView* bubble_delegate =
1090 new TestBubbleDelegateView(anchor->client_view());
1091 Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
1092 EXPECT_TRUE(bubble_delegate->reset_controls_called_);
1093 bubble_widget->Show();
1094 bubble_widget->CloseNow();
1095
1096 anchor->Hide();
1097 anchor->CloseNow();
1098 }
1099
1100 // Desktop native widget Aura tests are for non Chrome OS platforms.
1101 #if !defined(OS_CHROMEOS)
1102 // Test to ensure that after minimize, view width is set to zero.
1103 TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
1104 // Create a widget.
1105 Widget widget;
1106 Widget::InitParams init_params =
1107 CreateParams(Widget::InitParams::TYPE_WINDOW);
1108 init_params.show_state = ui::SHOW_STATE_NORMAL;
1109 gfx::Rect initial_bounds(0, 0, 300, 400);
1110 init_params.bounds = initial_bounds;
1111 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1112 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1113 widget.Init(init_params);
1114 NonClientView* non_client_view = widget.non_client_view();
1115 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1116 non_client_view->SetFrameView(frame_view);
1117 widget.Show();
1118 widget.Minimize();
1119 EXPECT_EQ(0, frame_view->width());
1120 }
1121
1122 // This class validates whether paints are received for a visible Widget.
1123 // To achieve this it overrides the Show and Close methods on the Widget class
1124 // and sets state whether subsequent paints are expected.
1125 class DesktopAuraTestValidPaintWidget : public views::Widget {
1126 public:
1127 DesktopAuraTestValidPaintWidget()
1128 : received_paint_(false),
1129 expect_paint_(true),
1130 received_paint_while_hidden_(false) {}
1131
1132 virtual ~DesktopAuraTestValidPaintWidget() {}
1133
1134 void InitForTest(Widget::InitParams create_params);
1135
1136 virtual void Show() override {
1137 expect_paint_ = true;
1138 views::Widget::Show();
1139 }
1140
1141 virtual void Close() override {
1142 expect_paint_ = false;
1143 views::Widget::Close();
1144 }
1145
1146 void Hide() {
1147 expect_paint_ = false;
1148 views::Widget::Hide();
1149 }
1150
1151 virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) override {
1152 received_paint_ = true;
1153 EXPECT_TRUE(expect_paint_);
1154 if (!expect_paint_)
1155 received_paint_while_hidden_ = true;
1156 views::Widget::OnNativeWidgetPaint(canvas);
1157 }
1158
1159 bool ReadReceivedPaintAndReset() {
1160 bool result = received_paint_;
1161 received_paint_ = false;
1162 return result;
1163 }
1164
1165 bool received_paint_while_hidden() const {
1166 return received_paint_while_hidden_;
1167 }
1168
1169 private:
1170 bool received_paint_;
1171 bool expect_paint_;
1172 bool received_paint_while_hidden_;
1173
1174 DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
1175 };
1176
1177 void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) {
1178 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1179 init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1180 init_params.native_widget = new PlatformDesktopNativeWidget(this);
1181 Init(init_params);
1182
1183 View* contents_view = new View;
1184 contents_view->SetFocusable(true);
1185 SetContentsView(contents_view);
1186
1187 Show();
1188 Activate();
1189 }
1190
1191 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
1192 DesktopAuraTestValidPaintWidget widget;
1193 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1194 RunPendingMessages();
1195 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1196 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1197 widget.Close();
1198 RunPendingMessages();
1199 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1200 EXPECT_FALSE(widget.received_paint_while_hidden());
1201 }
1202
1203 TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
1204 DesktopAuraTestValidPaintWidget widget;
1205 widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
1206 RunPendingMessages();
1207 EXPECT_TRUE(widget.ReadReceivedPaintAndReset());
1208 widget.SchedulePaintInRect(widget.GetRestoredBounds());
1209 widget.Hide();
1210 RunPendingMessages();
1211 EXPECT_FALSE(widget.ReadReceivedPaintAndReset());
1212 EXPECT_FALSE(widget.received_paint_while_hidden());
1213 widget.Close();
1214 }
1215
1216 // Test to ensure that the aura Window's visiblity state is set to visible if
1217 // the underlying widget is hidden and then shown.
1218 TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
1219 // Create a widget.
1220 Widget widget;
1221 Widget::InitParams init_params =
1222 CreateParams(Widget::InitParams::TYPE_WINDOW);
1223 init_params.show_state = ui::SHOW_STATE_NORMAL;
1224 gfx::Rect initial_bounds(0, 0, 300, 400);
1225 init_params.bounds = initial_bounds;
1226 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1227 init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
1228 widget.Init(init_params);
1229 NonClientView* non_client_view = widget.non_client_view();
1230 NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
1231 non_client_view->SetFrameView(frame_view);
1232
1233 widget.Show();
1234 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1235 widget.Hide();
1236 EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
1237 widget.Show();
1238 EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
1239 }
1240
1241 // The following code verifies we can correctly destroy a Widget from a mouse
1242 // enter/exit. We could test move/drag/enter/exit but in general we don't run
1243 // nested message loops from such events, nor has the code ever really dealt
1244 // with this situation.
1245
1246 // Generates two moves (first generates enter, second real move), a press, drag
1247 // and release stopping at |last_event_type|.
1248 void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
1249 const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
1250 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
1251 screen_bounds.CenterPoint(), 0, 0);
1252 ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
1253 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
1254 if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
1255 return;
1256 details = dispatcher->OnEventFromSource(&move_event);
1257 if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
1258 return;
1259
1260 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
1261 screen_bounds.CenterPoint(), 0, 0);
1262 details = dispatcher->OnEventFromSource(&press_event);
1263 if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
1264 return;
1265
1266 gfx::Point end_point(screen_bounds.CenterPoint());
1267 end_point.Offset(1, 1);
1268 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
1269 details = dispatcher->OnEventFromSource(&drag_event);
1270 if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
1271 return;
1272
1273 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
1274 0);
1275 details = dispatcher->OnEventFromSource(&release_event);
1276 if (details.dispatcher_destroyed)
1277 return;
1278 }
1279
1280 // Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
1281 void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
1282 ui::EventType last_event_type) {
1283 // |widget| is deleted by CloseWidgetView.
1284 Widget* widget = new Widget;
1285 Widget::InitParams params =
1286 test->CreateParams(Widget::InitParams::TYPE_POPUP);
1287 params.native_widget = new PlatformDesktopNativeWidget(widget);
1288 params.bounds = gfx::Rect(0, 0, 50, 100);
1289 widget->Init(params);
1290 widget->SetContentsView(new CloseWidgetView(last_event_type));
1291 widget->Show();
1292 GenerateMouseEvents(widget, last_event_type);
1293 }
1294
1295 // Verifies deleting the widget from a mouse pressed event doesn't crash.
1296 TEST_F(WidgetTest, CloseWidgetDuringMousePress) {
1297 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_PRESSED);
1298 }
1299
1300 // Verifies deleting the widget from a mouse released event doesn't crash.
1301 TEST_F(WidgetTest, CloseWidgetDuringMouseReleased) {
1302 RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
1303 }
1304
1305 #endif // !defined(OS_CHROMEOS)
1306
1307 // Tests that wheel events generated from scroll events are targetted to the
1308 // views under the cursor when the focused view does not processed them.
1309 TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
1310 EventCountView* cursor_view = new EventCountView;
1311 cursor_view->SetBounds(60, 0, 50, 40);
1312
1313 Widget* widget = CreateTopLevelPlatformWidget();
1314 widget->GetRootView()->AddChildView(cursor_view);
1315
1316 // Generate a scroll event on the cursor view.
1317 ui::ScrollEvent scroll(ui::ET_SCROLL,
1318 gfx::Point(65, 5),
1319 ui::EventTimeForNow(),
1320 0,
1321 0, 20,
1322 0, 20,
1323 2);
1324 widget->OnScrollEvent(&scroll);
1325
1326 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
1327 EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1328
1329 cursor_view->ResetCounts();
1330
1331 ui::ScrollEvent scroll2(ui::ET_SCROLL,
1332 gfx::Point(5, 5),
1333 ui::EventTimeForNow(),
1334 0,
1335 0, 20,
1336 0, 20,
1337 2);
1338 widget->OnScrollEvent(&scroll2);
1339
1340 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
1341 EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
1342
1343 widget->CloseNow();
1344 }
1345
1346 // Tests that if a scroll-begin gesture is not handled, then subsequent scroll
1347 // events are not dispatched to any view.
1348 TEST_F(WidgetTest, GestureScrollEventDispatching) {
1349 EventCountView* noscroll_view = new EventCountView;
1350 EventCountView* scroll_view = new ScrollableEventCountView;
1351
1352 noscroll_view->SetBounds(0, 0, 50, 40);
1353 scroll_view->SetBounds(60, 0, 40, 40);
1354
1355 Widget* widget = CreateTopLevelPlatformWidget();
1356 widget->GetRootView()->AddChildView(noscroll_view);
1357 widget->GetRootView()->AddChildView(scroll_view);
1358
1359 {
1360 ui::GestureEvent begin(
1361 5,
1362 5,
1363 0,
1364 base::TimeDelta(),
1365 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1366 widget->OnGestureEvent(&begin);
1367 ui::GestureEvent update(
1368 25,
1369 15,
1370 0,
1371 base::TimeDelta(),
1372 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1373 widget->OnGestureEvent(&update);
1374 ui::GestureEvent end(25,
1375 15,
1376 0,
1377 base::TimeDelta(),
1378 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1379 widget->OnGestureEvent(&end);
1380
1381 EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1382 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1383 EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1384 }
1385
1386 {
1387 ui::GestureEvent begin(
1388 65,
1389 5,
1390 0,
1391 base::TimeDelta(),
1392 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
1393 widget->OnGestureEvent(&begin);
1394 ui::GestureEvent update(
1395 85,
1396 15,
1397 0,
1398 base::TimeDelta(),
1399 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10));
1400 widget->OnGestureEvent(&update);
1401 ui::GestureEvent end(85,
1402 15,
1403 0,
1404 base::TimeDelta(),
1405 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
1406 widget->OnGestureEvent(&end);
1407
1408 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
1409 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
1410 EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
1411 }
1412
1413 widget->CloseNow();
1414 }
1415
1416 // Tests that event-handlers installed on the RootView get triggered correctly.
1417 // TODO(tdanderson): Clean up this test as part of crbug.com/355680.
1418 TEST_F(WidgetTest, EventHandlersOnRootView) {
1419 Widget* widget = CreateTopLevelNativeWidget();
1420 View* root_view = widget->GetRootView();
1421
1422 scoped_ptr<EventCountView> view(new EventCountView());
1423 view->set_owned_by_client();
1424 view->SetBounds(0, 0, 20, 20);
1425 root_view->AddChildView(view.get());
1426
1427 EventCountHandler h1;
1428 root_view->AddPreTargetHandler(&h1);
1429
1430 EventCountHandler h2;
1431 root_view->AddPostTargetHandler(&h2);
1432
1433 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
1434 widget->Show();
1435
1436 // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should
1437 // bubble up the views hierarchy to be re-dispatched on the root view.
1438 ui::ScrollEvent scroll(ui::ET_SCROLL,
1439 gfx::Point(5, 5),
1440 ui::EventTimeForNow(),
1441 0,
1442 0, 20,
1443 0, 20,
1444 2);
1445 widget->OnScrollEvent(&scroll);
1446 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
1447 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1448 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
1449
1450 // Unhandled scroll events are turned into wheel events and re-dispatched.
1451 EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1452 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
1453 EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1454
1455 h1.ResetCounts();
1456 view->ResetCounts();
1457 h2.ResetCounts();
1458
1459 // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and
1460 // should bubble up the views hierarchy to be re-dispatched on the root view.
1461 ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
1462 gfx::Point(5, 5),
1463 ui::EventTimeForNow(),
1464 0,
1465 0, 20,
1466 0, 20,
1467 2);
1468 widget->OnScrollEvent(&fling);
1469 EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
1470 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
1471 EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
1472
1473 // Unhandled scroll events which are not of type ui::ET_SCROLL should not
1474 // be turned into wheel events and re-dispatched.
1475 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1476 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1477 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1478
1479 h1.ResetCounts();
1480 view->ResetCounts();
1481 h2.ResetCounts();
1482
1483 // Change the handle mode of |view| so that events are marked as handled at
1484 // the target phase.
1485 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
1486
1487 // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event.
1488 // The events are handled at the target phase and should not reach the
1489 // post-target handler.
1490 ui::GestureEvent tap_down(5,
1491 5,
1492 0,
1493 ui::EventTimeForNow(),
1494 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1495 widget->OnGestureEvent(&tap_down);
1496 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1497 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1498 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
1499
1500 ui::GestureEvent tap_cancel(
1501 5,
1502 5,
1503 0,
1504 ui::EventTimeForNow(),
1505 ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL));
1506 widget->OnGestureEvent(&tap_cancel);
1507 EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1508 EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1509 EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
1510
1511 h1.ResetCounts();
1512 view->ResetCounts();
1513 h2.ResetCounts();
1514
1515 // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase
1516 // and should not reach the post-target handler.
1517 ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
1518 gfx::Point(5, 5),
1519 ui::EventTimeForNow(),
1520 0,
1521 0, 20,
1522 0, 20,
1523 2);
1524 widget->OnScrollEvent(&consumed_scroll);
1525 EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
1526 EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
1527 EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
1528
1529 // Handled scroll events are not turned into wheel events and re-dispatched.
1530 EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
1531 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
1532 EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
1533
1534 widget->CloseNow();
1535 }
1536
1537 TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
1538 Widget* widget = CreateTopLevelNativeWidget();
1539 View* root_view = widget->GetRootView();
1540
1541 EventCountView* v1 = new EventCountView();
1542 v1->SetBounds(0, 0, 10, 10);
1543 root_view->AddChildView(v1);
1544 EventCountView* v2 = new EventCountView();
1545 v2->SetBounds(0, 10, 10, 10);
1546 root_view->AddChildView(v2);
1547
1548 gfx::Point cursor_location(5, 5);
1549 ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
1550 ui::EF_NONE, ui::EF_NONE);
1551 widget->OnMouseEvent(&move);
1552
1553 EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
1554 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1555
1556 delete v1;
1557 v2->SetBounds(0, 0, 10, 10);
1558 EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1559
1560 widget->SynthesizeMouseMoveEvent();
1561 EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
1562 }
1563
1564 namespace {
1565
1566 // ui::EventHandler which handles all mouse press events.
1567 class MousePressEventConsumer : public ui::EventHandler {
1568 public:
1569 explicit MousePressEventConsumer() {
1570 }
1571
1572 virtual ~MousePressEventConsumer() {
1573 }
1574
1575 private:
1576 // ui::EventHandler:
1577 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1578 if (event->type() == ui::ET_MOUSE_PRESSED)
1579 event->SetHandled();
1580 }
1581
1582 DISALLOW_COPY_AND_ASSIGN(MousePressEventConsumer);
1583 };
1584
1585 } // namespace
1586
1587 // Test that mouse presses and mouse releases are dispatched normally when a
1588 // touch is down.
1589 TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
1590 Widget* widget = CreateTopLevelNativeWidget();
1591 widget->Show();
1592 widget->SetSize(gfx::Size(300, 300));
1593
1594 EventCountView* event_count_view = new EventCountView();
1595 event_count_view->SetBounds(0, 0, 300, 300);
1596 widget->GetRootView()->AddChildView(event_count_view);
1597
1598 MousePressEventConsumer consumer;
1599 event_count_view->AddPostTargetHandler(&consumer);
1600
1601 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1602 generator.PressTouch();
1603 generator.ClickLeftButton();
1604
1605 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
1606 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
1607
1608 widget->CloseNow();
1609 }
1610
1611 // Used by SingleWindowClosing to count number of times WindowClosing() has
1612 // been invoked.
1613 class ClosingDelegate : public WidgetDelegate {
1614 public:
1615 ClosingDelegate() : count_(0), widget_(NULL) {}
1616
1617 int count() const { return count_; }
1618
1619 void set_widget(views::Widget* widget) { widget_ = widget; }
1620
1621 // WidgetDelegate overrides:
1622 virtual Widget* GetWidget() override { return widget_; }
1623 virtual const Widget* GetWidget() const override { return widget_; }
1624 virtual void WindowClosing() override {
1625 count_++;
1626 }
1627
1628 private:
1629 int count_;
1630 views::Widget* widget_;
1631
1632 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
1633 };
1634
1635 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget
1636 // is closed.
1637 TEST_F(WidgetTest, SingleWindowClosing) {
1638 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
1639 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1640 Widget::InitParams init_params =
1641 CreateParams(Widget::InitParams::TYPE_WINDOW);
1642 init_params.bounds = gfx::Rect(0, 0, 200, 200);
1643 init_params.delegate = delegate.get();
1644 #if !defined(OS_CHROMEOS)
1645 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1646 #endif
1647 widget->Init(init_params);
1648 EXPECT_EQ(0, delegate->count());
1649 widget->CloseNow();
1650 EXPECT_EQ(1, delegate->count());
1651 }
1652
1653 class WidgetWindowTitleTest : public WidgetTest {
1654 protected:
1655 void RunTest(bool desktop_native_widget) {
1656 Widget* widget = new Widget(); // Destroyed by CloseNow() below.
1657 Widget::InitParams init_params =
1658 CreateParams(Widget::InitParams::TYPE_WINDOW);
1659 widget->Init(init_params);
1660
1661 #if !defined(OS_CHROMEOS)
1662 if (desktop_native_widget)
1663 init_params.native_widget = new PlatformDesktopNativeWidget(widget);
1664 #else
1665 DCHECK(!desktop_native_widget)
1666 << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
1667 #endif
1668
1669 internal::NativeWidgetPrivate* native_widget =
1670 widget->native_widget_private();
1671
1672 base::string16 empty;
1673 base::string16 s1(base::UTF8ToUTF16("Title1"));
1674 base::string16 s2(base::UTF8ToUTF16("Title2"));
1675 base::string16 s3(base::UTF8ToUTF16("TitleLong"));
1676
1677 // The widget starts with no title, setting empty should not change
1678 // anything.
1679 EXPECT_FALSE(native_widget->SetWindowTitle(empty));
1680 // Setting the title to something non-empty should cause a change.
1681 EXPECT_TRUE(native_widget->SetWindowTitle(s1));
1682 // Setting the title to something else with the same length should cause a
1683 // change.
1684 EXPECT_TRUE(native_widget->SetWindowTitle(s2));
1685 // Setting the title to something else with a different length should cause
1686 // a change.
1687 EXPECT_TRUE(native_widget->SetWindowTitle(s3));
1688 // Setting the title to the same thing twice should not cause a change.
1689 EXPECT_FALSE(native_widget->SetWindowTitle(s3));
1690
1691 widget->CloseNow();
1692 }
1693 };
1694
1695 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
1696 // Use the default NativeWidget.
1697 bool desktop_native_widget = false;
1698 RunTest(desktop_native_widget);
1699 }
1700
1701 // DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
1702 #if !defined(OS_CHROMEOS)
1703 TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
1704 // Override to use a DesktopNativeWidget.
1705 bool desktop_native_widget = true;
1706 RunTest(desktop_native_widget);
1707 }
1708 #endif // !OS_CHROMEOS
1709
1710 TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
1711 Widget* widget = new Widget;
1712 Widget::InitParams params =
1713 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1714 widget->Init(params);
1715
1716 widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
1717
1718 widget->SetSize(gfx::Size(100, 100));
1719 widget->Show();
1720
1721 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1722
1723 WidgetDeletionObserver deletion_observer(widget);
1724 generator.ClickLeftButton();
1725 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1726
1727 // Yay we did not crash!
1728 }
1729
1730 TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
1731 Widget* widget = new Widget;
1732 Widget::InitParams params =
1733 CreateParams(views::Widget::InitParams::TYPE_POPUP);
1734 widget->Init(params);
1735
1736 widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
1737
1738 widget->SetSize(gfx::Size(100, 100));
1739 widget->Show();
1740
1741 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
1742
1743 WidgetDeletionObserver deletion_observer(widget);
1744 generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
1745 EXPECT_FALSE(deletion_observer.IsWidgetAlive());
1746
1747 // Yay we did not crash!
1748 }
1749
1750 // See description of RunGetNativeThemeFromDestructor() for details.
1751 class GetNativeThemeFromDestructorView : public WidgetDelegateView {
1752 public:
1753 GetNativeThemeFromDestructorView() {}
1754 virtual ~GetNativeThemeFromDestructorView() {
1755 VerifyNativeTheme();
1756 }
1757
1758 virtual View* GetContentsView() override {
1759 return this;
1760 }
1761
1762 private:
1763 void VerifyNativeTheme() {
1764 ASSERT_TRUE(GetNativeTheme() != NULL);
1765 }
1766
1767 DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
1768 };
1769
1770 // Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
1771 // crash. |is_first_run| is true if this is the first call. A return value of
1772 // true indicates this should be run again with a value of false.
1773 // First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
1774 bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
1775 bool is_first_run) {
1776 bool needs_second_run = false;
1777 // Destroyed by CloseNow() below.
1778 Widget* widget = new Widget;
1779 Widget::InitParams params(in_params);
1780 // Deletes itself when the Widget is destroyed.
1781 params.delegate = new GetNativeThemeFromDestructorView;
1782 #if !defined(OS_CHROMEOS)
1783 if (is_first_run) {
1784 params.native_widget = new PlatformDesktopNativeWidget(widget);
1785 needs_second_run = true;
1786 }
1787 #endif
1788 widget->Init(params);
1789 widget->CloseNow();
1790 return needs_second_run;
1791 }
1792
1793 // See description of RunGetNativeThemeFromDestructor() for details.
1794 TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
1795 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1796 if (RunGetNativeThemeFromDestructor(params, true))
1797 RunGetNativeThemeFromDestructor(params, false);
1798 }
1799
1800 // Used by HideCloseDestroy. Allows setting a boolean when the widget is
1801 // destroyed.
1802 class CloseDestroysWidget : public Widget {
1803 public:
1804 explicit CloseDestroysWidget(bool* destroyed)
1805 : destroyed_(destroyed) {
1806 }
1807
1808 virtual ~CloseDestroysWidget() {
1809 if (destroyed_) {
1810 *destroyed_ = true;
1811 base::MessageLoop::current()->QuitNow();
1812 }
1813 }
1814
1815 void Detach() { destroyed_ = NULL; }
1816
1817 private:
1818 // If non-null set to true from destructor.
1819 bool* destroyed_;
1820
1821 DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
1822 };
1823
1824 // An observer that registers that an animation has ended.
1825 class AnimationEndObserver : public ui::ImplicitAnimationObserver {
1826 public:
1827 AnimationEndObserver() : animation_completed_(false) {}
1828 virtual ~AnimationEndObserver() {}
1829
1830 bool animation_completed() const { return animation_completed_; }
1831
1832 // ui::ImplicitAnimationObserver:
1833 virtual void OnImplicitAnimationsCompleted() override {
1834 animation_completed_ = true;
1835 }
1836
1837 private:
1838 bool animation_completed_;
1839
1840 DISALLOW_COPY_AND_ASSIGN(AnimationEndObserver);
1841 };
1842
1843 // An observer that registers the bounds of a widget on destruction.
1844 class WidgetBoundsObserver : public WidgetObserver {
1845 public:
1846 WidgetBoundsObserver() {}
1847 virtual ~WidgetBoundsObserver() {}
1848
1849 gfx::Rect bounds() { return bounds_; }
1850
1851 // WidgetObserver:
1852 virtual void OnWidgetDestroying(Widget* widget) override {
1853 bounds_ = widget->GetWindowBoundsInScreen();
1854 }
1855
1856 private:
1857 gfx::Rect bounds_;
1858
1859 DISALLOW_COPY_AND_ASSIGN(WidgetBoundsObserver);
1860 };
1861
1862 // Verifies Close() results in destroying.
1863 TEST_F(WidgetTest, CloseDestroys) {
1864 bool destroyed = false;
1865 CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
1866 Widget::InitParams params =
1867 CreateParams(views::Widget::InitParams::TYPE_MENU);
1868 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
1869 #if !defined(OS_CHROMEOS)
1870 params.native_widget = new PlatformDesktopNativeWidget(widget);
1871 #endif
1872 widget->Init(params);
1873 widget->Show();
1874 widget->Hide();
1875 widget->Close();
1876 EXPECT_FALSE(destroyed);
1877 // Run the message loop as Close() asynchronously deletes.
1878 base::RunLoop().Run();
1879 EXPECT_TRUE(destroyed);
1880 // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
1881 if (!destroyed) {
1882 widget->Detach();
1883 widget->CloseNow();
1884 }
1885 }
1886
1887 // Tests that killing a widget while animating it does not crash.
1888 TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
1889 scoped_ptr<Widget> widget(new Widget);
1890 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1891 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1892 params.bounds = gfx::Rect(50, 50, 250, 250);
1893 widget->Init(params);
1894 AnimationEndObserver animation_observer;
1895 WidgetBoundsObserver widget_observer;
1896 gfx::Rect bounds(0, 0, 50, 50);
1897 {
1898 // Normal animations for tests have ZERO_DURATION, make sure we are actually
1899 // animating the movement.
1900 ui::ScopedAnimationDurationScaleMode animation_scale_mode(
1901 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1902 ui::ScopedLayerAnimationSettings animation_settings(
1903 widget->GetLayer()->GetAnimator());
1904 animation_settings.AddObserver(&animation_observer);
1905 widget->AddObserver(&widget_observer);
1906 widget->Show();
1907
1908 // Animate the bounds change.
1909 widget->SetBounds(bounds);
1910 widget.reset();
1911 EXPECT_FALSE(animation_observer.animation_completed());
1912 }
1913 EXPECT_TRUE(animation_observer.animation_completed());
1914 EXPECT_EQ(widget_observer.bounds(), bounds);
1915 }
1916
1917 // A view that consumes mouse-pressed event and gesture-tap-down events.
1918 class RootViewTestView : public View {
1919 public:
1920 RootViewTestView(): View() {}
1921
1922 private:
1923 virtual bool OnMousePressed(const ui::MouseEvent& event) override {
1924 return true;
1925 }
1926
1927 virtual void OnGestureEvent(ui::GestureEvent* event) override {
1928 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
1929 event->SetHandled();
1930 }
1931 };
1932
1933 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
1934 // Fails on chromium.webkit Windows bot, see crbug.com/264872.
1935 #if defined(OS_WIN)
1936 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1937 DISABLED_TestRootViewHandlersWhenHidden
1938 #else
1939 #define MAYBE_DisableTestRootViewHandlersWhenHidden\
1940 TestRootViewHandlersWhenHidden
1941 #endif
1942 TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
1943 Widget* widget = CreateTopLevelNativeWidget();
1944 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
1945 View* view = new RootViewTestView();
1946 view->SetBounds(0, 0, 300, 300);
1947 internal::RootView* root_view =
1948 static_cast<internal::RootView*>(widget->GetRootView());
1949 root_view->AddChildView(view);
1950
1951 // Check RootView::mouse_pressed_handler_.
1952 widget->Show();
1953 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1954 gfx::Point click_location(45, 15);
1955 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
1956 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
1957 widget->OnMouseEvent(&press);
1958 EXPECT_EQ(view, GetMousePressedHandler(root_view));
1959 widget->Hide();
1960 EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
1961
1962 // Check RootView::mouse_move_handler_.
1963 widget->Show();
1964 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1965 gfx::Point move_location(45, 15);
1966 ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
1967 widget->OnMouseEvent(&move);
1968 EXPECT_EQ(view, GetMouseMoveHandler(root_view));
1969 widget->Hide();
1970 EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
1971
1972 // Check RootView::gesture_handler_.
1973 widget->Show();
1974 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1975 ui::GestureEvent tap_down(15,
1976 15,
1977 0,
1978 base::TimeDelta(),
1979 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1980 widget->OnGestureEvent(&tap_down);
1981 EXPECT_EQ(view, GetGestureHandler(root_view));
1982 widget->Hide();
1983 EXPECT_EQ(NULL, GetGestureHandler(root_view));
1984
1985 widget->Close();
1986 }
1987
1988 // Convenience to make constructing a GestureEvent simpler.
1989 class GestureEventForTest : public ui::GestureEvent {
1990 public:
1991 GestureEventForTest(ui::EventType type, int x, int y)
1992 : GestureEvent(x,
1993 y,
1994 0,
1995 base::TimeDelta(),
1996 ui::GestureEventDetails(type)) {}
1997
1998 GestureEventForTest(ui::GestureEventDetails details, int x, int y)
1999 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
2000 };
2001
2002 // Tests that the |gesture_handler_| member in RootView is always NULL
2003 // after the dispatch of a ui::ET_GESTURE_END event corresponding to
2004 // the release of the final touch point on the screen, but that
2005 // ui::ET_GESTURE_END events corresponding to the removal of any other touch
2006 // point do not modify |gesture_handler_|.
2007 TEST_F(WidgetTest, GestureEndEvents) {
2008 Widget* widget = CreateTopLevelNativeWidget();
2009 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2010 EventCountView* view = new EventCountView();
2011 view->SetBounds(0, 0, 300, 300);
2012 internal::RootView* root_view =
2013 static_cast<internal::RootView*>(widget->GetRootView());
2014 root_view->AddChildView(view);
2015 widget->Show();
2016
2017 // If no gesture handler is set, a ui::ET_GESTURE_END event should not set
2018 // the gesture handler.
2019 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2020 GestureEventForTest end(ui::ET_GESTURE_END, 15, 15);
2021 widget->OnGestureEvent(&end);
2022 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2023
2024 // Change the handle mode of |view| to indicate that it would like
2025 // to handle all events, then send a GESTURE_TAP to set the gesture handler.
2026 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
2027 GestureEventForTest tap(ui::ET_GESTURE_TAP, 15, 15);
2028 widget->OnGestureEvent(&tap);
2029 EXPECT_TRUE(tap.handled());
2030 EXPECT_EQ(view, GetGestureHandler(root_view));
2031
2032 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2033 // corresponding to a second touch point, but should be reset to NULL by a
2034 // ui::ET_GESTURE_END corresponding to the final touch point.
2035 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2036 details.set_touch_points(2);
2037 GestureEventForTest end_second_touch_point(details, 15, 15);
2038 widget->OnGestureEvent(&end_second_touch_point);
2039 EXPECT_EQ(view, GetGestureHandler(root_view));
2040
2041 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2042 widget->OnGestureEvent(&end);
2043 EXPECT_TRUE(end.handled());
2044 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2045
2046 // Send a GESTURE_TAP to set the gesture handler, then change the handle
2047 // mode of |view| to indicate that it does not want to handle any
2048 // further events.
2049 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 15, 15);
2050 widget->OnGestureEvent(&tap);
2051 EXPECT_TRUE(tap.handled());
2052 EXPECT_EQ(view, GetGestureHandler(root_view));
2053 view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2054
2055 // The gesture handler should remain unchanged on a ui::ET_GESTURE_END
2056 // corresponding to a second touch point, but should be reset to NULL by a
2057 // ui::ET_GESTURE_END corresponding to the final touch point.
2058 end_second_touch_point = GestureEventForTest(details, 15, 15);
2059 widget->OnGestureEvent(&end_second_touch_point);
2060 EXPECT_EQ(view, GetGestureHandler(root_view));
2061
2062 end = GestureEventForTest(ui::ET_GESTURE_END, 15, 15);
2063 widget->OnGestureEvent(&end);
2064 EXPECT_FALSE(end.handled());
2065 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2066
2067 widget->Close();
2068 }
2069
2070 // Tests that gesture events which should not be processed (because
2071 // RootView::OnEventProcessingStarted() has marked them as handled) are not
2072 // dispatched to any views.
2073 TEST_F(WidgetTest, GestureEventsNotProcessed) {
2074 Widget* widget = CreateTopLevelNativeWidget();
2075 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2076
2077 // Define a hierarchy of four views (coordinates are in
2078 // their parent coordinate space).
2079 // v1 (0, 0, 300, 300)
2080 // v2 (0, 0, 100, 100)
2081 // v3 (0, 0, 50, 50)
2082 // v4(0, 0, 10, 10)
2083 EventCountView* v1 = new EventCountView();
2084 v1->SetBounds(0, 0, 300, 300);
2085 EventCountView* v2 = new EventCountView();
2086 v2->SetBounds(0, 0, 100, 100);
2087 EventCountView* v3 = new EventCountView();
2088 v3->SetBounds(0, 0, 50, 50);
2089 EventCountView* v4 = new EventCountView();
2090 v4->SetBounds(0, 0, 10, 10);
2091 internal::RootView* root_view =
2092 static_cast<internal::RootView*>(widget->GetRootView());
2093 root_view->AddChildView(v1);
2094 v1->AddChildView(v2);
2095 v2->AddChildView(v3);
2096 v3->AddChildView(v4);
2097
2098 widget->Show();
2099
2100 // ui::ET_GESTURE_BEGIN events should never be seen by any view, but
2101 // they should be marked as handled by OnEventProcessingStarted().
2102 GestureEventForTest begin(ui::ET_GESTURE_BEGIN, 5, 5);
2103 widget->OnGestureEvent(&begin);
2104 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
2105 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
2106 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
2107 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
2108 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2109 EXPECT_TRUE(begin.handled());
2110 v1->ResetCounts();
2111 v2->ResetCounts();
2112 v3->ResetCounts();
2113 v4->ResetCounts();
2114
2115 // ui::ET_GESTURE_END events should not be seen by any view when there is
2116 // no default gesture handler set, but they should be marked as handled by
2117 // OnEventProcessingStarted().
2118 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2119 widget->OnGestureEvent(&end);
2120 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2121 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2122 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2123 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2124 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2125 EXPECT_TRUE(end.handled());
2126 v1->ResetCounts();
2127 v2->ResetCounts();
2128 v3->ResetCounts();
2129 v4->ResetCounts();
2130
2131 // ui::ET_GESTURE_END events not corresponding to the release of the
2132 // final touch point should never be seen by any view, but they should
2133 // be marked as handled by OnEventProcessingStarted().
2134 ui::GestureEventDetails details(ui::ET_GESTURE_END);
2135 details.set_touch_points(2);
2136 GestureEventForTest end_second_touch_point(details, 5, 5);
2137 widget->OnGestureEvent(&end_second_touch_point);
2138 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2139 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2140 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2141 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2142 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2143 EXPECT_TRUE(end_second_touch_point.handled());
2144 v1->ResetCounts();
2145 v2->ResetCounts();
2146 v3->ResetCounts();
2147 v4->ResetCounts();
2148
2149 // ui::ET_GESTURE_SCROLL_UPDATE events should never be seen by any view when
2150 // there is no default gesture handler set, but they should be marked as
2151 // handled by OnEventProcessingStarted().
2152 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2153 widget->OnGestureEvent(&scroll_update);
2154 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2155 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2156 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2157 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2158 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2159 EXPECT_TRUE(scroll_update.handled());
2160 v1->ResetCounts();
2161 v2->ResetCounts();
2162 v3->ResetCounts();
2163 v4->ResetCounts();
2164
2165 // ui::ET_GESTURE_SCROLL_END events should never be seen by any view when
2166 // there is no default gesture handler set, but they should be marked as
2167 // handled by OnEventProcessingStarted().
2168 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2169 widget->OnGestureEvent(&scroll_end);
2170 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2171 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2172 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2173 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2174 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2175 EXPECT_TRUE(scroll_end.handled());
2176 v1->ResetCounts();
2177 v2->ResetCounts();
2178 v3->ResetCounts();
2179 v4->ResetCounts();
2180
2181 // ui::ET_SCROLL_FLING_START events should never be seen by any view when
2182 // there is no default gesture handler set, but they should be marked as
2183 // handled by OnEventProcessingStarted().
2184 GestureEventForTest scroll_fling_start(ui::ET_SCROLL_FLING_START, 5, 5);
2185 widget->OnGestureEvent(&scroll_fling_start);
2186 EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
2187 EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
2188 EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
2189 EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
2190 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2191 EXPECT_TRUE(scroll_fling_start.handled());
2192 v1->ResetCounts();
2193 v2->ResetCounts();
2194 v3->ResetCounts();
2195 v4->ResetCounts();
2196
2197 widget->Close();
2198 }
2199
2200 // Tests that a (non-scroll) gesture event is dispatched to the correct views
2201 // in a view hierarchy and that the default gesture handler in RootView is set
2202 // correctly.
2203 TEST_F(WidgetTest, GestureEventDispatch) {
2204 Widget* widget = CreateTopLevelNativeWidget();
2205 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2206
2207 // Define a hierarchy of four views (coordinates are in
2208 // their parent coordinate space).
2209 // v1 (0, 0, 300, 300)
2210 // v2 (0, 0, 100, 100)
2211 // v3 (0, 0, 50, 50)
2212 // v4(0, 0, 10, 10)
2213 EventCountView* v1 = new EventCountView();
2214 v1->SetBounds(0, 0, 300, 300);
2215 EventCountView* v2 = new EventCountView();
2216 v2->SetBounds(0, 0, 100, 100);
2217 EventCountView* v3 = new EventCountView();
2218 v3->SetBounds(0, 0, 50, 50);
2219 EventCountView* v4 = new EventCountView();
2220 v4->SetBounds(0, 0, 10, 10);
2221 internal::RootView* root_view =
2222 static_cast<internal::RootView*>(widget->GetRootView());
2223 root_view->AddChildView(v1);
2224 v1->AddChildView(v2);
2225 v2->AddChildView(v3);
2226 v3->AddChildView(v4);
2227
2228 widget->Show();
2229
2230 // No gesture handler is set in the root view and none of the views in the
2231 // view hierarchy handle a ui::ET_GESTURE_TAP event. In this case the tap
2232 // event should be dispatched to all views in the hierarchy, the gesture
2233 // handler should remain unset, and the event should remain unhandled.
2234 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2235 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2236 widget->OnGestureEvent(&tap);
2237 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
2238 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
2239 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2240 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2241 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2242 EXPECT_FALSE(tap.handled());
2243
2244 // No gesture handler is set in the root view and |v1|, |v2|, and |v3| all
2245 // handle a ui::ET_GESTURE_TAP event. In this case the tap event should be
2246 // dispatched to |v4| and |v3|, the gesture handler should be set to |v3|,
2247 // and the event should be marked as handled.
2248 v1->ResetCounts();
2249 v2->ResetCounts();
2250 v3->ResetCounts();
2251 v4->ResetCounts();
2252 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2253 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2254 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2255 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2256 widget->OnGestureEvent(&tap);
2257 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2258 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2259 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2260 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2261 EXPECT_EQ(v3, GetGestureHandler(root_view));
2262 EXPECT_TRUE(tap.handled());
2263
2264 // The gesture handler is set to |v3| and all views handle all gesture event
2265 // types. In this case subsequent gesture events should only be dispatched to
2266 // |v3| and marked as handled. The gesture handler should remain as |v3|.
2267 v1->ResetCounts();
2268 v2->ResetCounts();
2269 v3->ResetCounts();
2270 v4->ResetCounts();
2271 v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
2272 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2273 widget->OnGestureEvent(&tap);
2274 EXPECT_TRUE(tap.handled());
2275 GestureEventForTest show_press(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
2276 widget->OnGestureEvent(&show_press);
2277 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2278 widget->OnGestureEvent(&tap);
2279 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2280 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2281 EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
2282 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2283 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2284 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2285 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2286 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
2287 EXPECT_TRUE(tap.handled());
2288 EXPECT_TRUE(show_press.handled());
2289 EXPECT_EQ(v3, GetGestureHandler(root_view));
2290
2291 // The gesture handler is set to |v3|, but |v3| does not handle
2292 // ui::ET_GESTURE_TAP events. In this case a tap gesture should be dispatched
2293 // only to |v3|, but the event should remain unhandled. The gesture handler
2294 // should remain as |v3|.
2295 v1->ResetCounts();
2296 v2->ResetCounts();
2297 v3->ResetCounts();
2298 v4->ResetCounts();
2299 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2300 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2301 widget->OnGestureEvent(&tap);
2302 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2303 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2304 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
2305 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2306 EXPECT_FALSE(tap.handled());
2307 EXPECT_EQ(v3, GetGestureHandler(root_view));
2308
2309 widget->Close();
2310 }
2311
2312 // Tests that gesture scroll events will change the default gesture handler in
2313 // RootView if the current handler to which they are dispatched does not handle
2314 // gesture scroll events.
2315 TEST_F(WidgetTest, ScrollGestureEventDispatch) {
2316 Widget* widget = CreateTopLevelNativeWidget();
2317 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2318
2319 // Define a hierarchy of four views (coordinates are in
2320 // their parent coordinate space).
2321 // v1 (0, 0, 300, 300)
2322 // v2 (0, 0, 100, 100)
2323 // v3 (0, 0, 50, 50)
2324 // v4(0, 0, 10, 10)
2325 EventCountView* v1 = new EventCountView();
2326 v1->SetBounds(0, 0, 300, 300);
2327 EventCountView* v2 = new EventCountView();
2328 v2->SetBounds(0, 0, 100, 100);
2329 EventCountView* v3 = new EventCountView();
2330 v3->SetBounds(0, 0, 50, 50);
2331 EventCountView* v4 = new EventCountView();
2332 v4->SetBounds(0, 0, 10, 10);
2333 internal::RootView* root_view =
2334 static_cast<internal::RootView*>(widget->GetRootView());
2335 root_view->AddChildView(v1);
2336 v1->AddChildView(v2);
2337 v2->AddChildView(v3);
2338 v3->AddChildView(v4);
2339
2340 widget->Show();
2341
2342 // Change the handle mode of |v3| to indicate that it would like to handle
2343 // gesture events.
2344 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2345
2346 // When no gesture handler is set, dispatching a ui::ET_GESTURE_TAP_DOWN
2347 // should bubble up the views hierarchy until it reaches the first view
2348 // that will handle it (|v3|) and then sets the handler to |v3|.
2349 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2350 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, 5, 5);
2351 widget->OnGestureEvent(&tap_down);
2352 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2353 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2354 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2355 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
2356 EXPECT_EQ(v3, GetGestureHandler(root_view));
2357 EXPECT_TRUE(tap_down.handled());
2358 v1->ResetCounts();
2359 v2->ResetCounts();
2360 v3->ResetCounts();
2361 v4->ResetCounts();
2362
2363 // A ui::ET_GESTURE_TAP_CANCEL event should be dispatched to |v3| directly.
2364 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
2365 widget->OnGestureEvent(&tap_cancel);
2366 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2367 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2368 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2369 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
2370 EXPECT_EQ(v3, GetGestureHandler(root_view));
2371 EXPECT_TRUE(tap_cancel.handled());
2372 v1->ResetCounts();
2373 v2->ResetCounts();
2374 v3->ResetCounts();
2375 v4->ResetCounts();
2376
2377 // Change the handle mode of |v3| to indicate that it would no longer like
2378 // to handle events, and change the mode of |v1| to indicate that it would
2379 // like to handle events.
2380 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2381 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2382
2383 // Dispatch a ui::ET_GESTURE_SCROLL_BEGIN event. Because the current gesture
2384 // handler (|v3|) does not handle scroll events, the event should bubble up
2385 // the views hierarchy until it reaches the first view that will handle
2386 // it (|v1|) and then sets the handler to |v1|.
2387 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
2388 widget->OnGestureEvent(&scroll_begin);
2389 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2390 EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2391 EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2392 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
2393 EXPECT_EQ(v1, GetGestureHandler(root_view));
2394 EXPECT_TRUE(scroll_begin.handled());
2395 v1->ResetCounts();
2396 v2->ResetCounts();
2397 v3->ResetCounts();
2398 v4->ResetCounts();
2399
2400 // A ui::ET_GESTURE_SCROLL_UPDATE event should be dispatched to |v1|
2401 // directly.
2402 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
2403 widget->OnGestureEvent(&scroll_update);
2404 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2405 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2406 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2407 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
2408 EXPECT_EQ(v1, GetGestureHandler(root_view));
2409 EXPECT_TRUE(scroll_update.handled());
2410 v1->ResetCounts();
2411 v2->ResetCounts();
2412 v3->ResetCounts();
2413 v4->ResetCounts();
2414
2415 // A ui::ET_GESTURE_SCROLL_END event should be dispatched to |v1|
2416 // directly and should not reset the gesture handler.
2417 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, 5, 5);
2418 widget->OnGestureEvent(&scroll_end);
2419 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2420 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2421 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2422 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
2423 EXPECT_EQ(v1, GetGestureHandler(root_view));
2424 EXPECT_TRUE(scroll_end.handled());
2425 v1->ResetCounts();
2426 v2->ResetCounts();
2427 v3->ResetCounts();
2428 v4->ResetCounts();
2429
2430 // A ui::ET_GESTURE_PINCH_BEGIN event (which is a non-scroll event) should
2431 // still be dispatched to |v1| directly.
2432 GestureEventForTest pinch_begin(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
2433 widget->OnGestureEvent(&pinch_begin);
2434 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2435 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2436 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2437 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
2438 EXPECT_EQ(v1, GetGestureHandler(root_view));
2439 EXPECT_TRUE(pinch_begin.handled());
2440 v1->ResetCounts();
2441 v2->ResetCounts();
2442 v3->ResetCounts();
2443 v4->ResetCounts();
2444
2445 // A ui::ET_GESTURE_END event should be dispatched to |v1| and should
2446 // set the gesture handler to NULL.
2447 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2448 widget->OnGestureEvent(&end);
2449 EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
2450 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2451 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2452 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2453 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2454 EXPECT_TRUE(end.handled());
2455
2456 widget->Close();
2457 }
2458
2459 // A class used in WidgetTest.GestureEventLocationWhileBubbling to verify
2460 // that when a gesture event bubbles up a View hierarchy, the location
2461 // of a gesture event seen by each View is in the local coordinate space
2462 // of that View.
2463 class GestureLocationView : public EventCountView {
2464 public:
2465 GestureLocationView() {}
2466 virtual ~GestureLocationView() {}
2467
2468 void set_expected_location(gfx::Point expected_location) {
2469 expected_location_ = expected_location;
2470 }
2471
2472 // EventCountView:
2473 virtual void OnGestureEvent(ui::GestureEvent* event) override {
2474 EventCountView::OnGestureEvent(event);
2475
2476 // Verify that the location of |event| is in the local coordinate
2477 // space of |this|.
2478 EXPECT_EQ(expected_location_, event->location());
2479 }
2480
2481 private:
2482 // The expected location of a gesture event dispatched to |this|.
2483 gfx::Point expected_location_;
2484
2485 DISALLOW_COPY_AND_ASSIGN(GestureLocationView);
2486 };
2487
2488 // Verifies that the location of a gesture event is always in the local
2489 // coordinate space of the View receiving the event while bubbling.
2490 TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
2491 Widget* widget = CreateTopLevelNativeWidget();
2492 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2493
2494 // Define a hierarchy of three views (coordinates shown below are in the
2495 // coordinate space of the root view, but the coordinates used for
2496 // SetBounds() are in their parent coordinate space).
2497 // v1 (50, 50, 150, 150)
2498 // v2 (100, 70, 50, 80)
2499 // v3 (120, 100, 10, 10)
2500 GestureLocationView* v1 = new GestureLocationView();
2501 v1->SetBounds(50, 50, 150, 150);
2502 GestureLocationView* v2 = new GestureLocationView();
2503 v2->SetBounds(50, 20, 50, 80);
2504 GestureLocationView* v3 = new GestureLocationView();
2505 v3->SetBounds(20, 30, 10, 10);
2506 internal::RootView* root_view =
2507 static_cast<internal::RootView*>(widget->GetRootView());
2508 root_view->AddChildView(v1);
2509 v1->AddChildView(v2);
2510 v2->AddChildView(v3);
2511
2512 widget->Show();
2513
2514 // Define a GESTURE_TAP event located at (125, 105) in root view coordinates.
2515 // This event is contained within all of |v1|, |v2|, and |v3|.
2516 gfx::Point location_in_root(125, 105);
2517 GestureEventForTest tap(
2518 ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
2519
2520 // Calculate the location of the event in the local coordinate spaces
2521 // of each of the views.
2522 gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
2523 EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
2524 gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
2525 EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
2526 gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
2527 EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
2528
2529 // Dispatch the event. When each view receives the event, its location should
2530 // be in the local coordinate space of that view (see the check made by
2531 // GestureLocationView). After dispatch is complete the event's location
2532 // should be in the root coordinate space.
2533 v1->set_expected_location(location_in_v1);
2534 v2->set_expected_location(location_in_v2);
2535 v3->set_expected_location(location_in_v3);
2536 widget->OnGestureEvent(&tap);
2537 EXPECT_EQ(location_in_root, tap.location());
2538
2539 // Verify that each view did in fact see the event.
2540 EventCountView* view1 = v1;
2541 EventCountView* view2 = v2;
2542 EventCountView* view3 = v3;
2543 EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
2544 EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
2545 EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
2546
2547 widget->Close();
2548 }
2549
2550 // Verifies that disabled views are permitted to be set as the default gesture
2551 // handler in RootView. Also verifies that gesture events targeted to a disabled
2552 // view are not actually dispatched to the view, but are still marked as
2553 // handled.
2554 TEST_F(WidgetTest, DisabledGestureEventTarget) {
2555 Widget* widget = CreateTopLevelNativeWidget();
2556 widget->SetBounds(gfx::Rect(0, 0, 300, 300));
2557
2558 // Define a hierarchy of four views (coordinates are in
2559 // their parent coordinate space).
2560 // v1 (0, 0, 300, 300)
2561 // v2 (0, 0, 100, 100)
2562 // v3 (0, 0, 50, 50)
2563 // v4(0, 0, 10, 10)
2564 EventCountView* v1 = new EventCountView();
2565 v1->SetBounds(0, 0, 300, 300);
2566 EventCountView* v2 = new EventCountView();
2567 v2->SetBounds(0, 0, 100, 100);
2568 EventCountView* v3 = new EventCountView();
2569 v3->SetBounds(0, 0, 50, 50);
2570 EventCountView* v4 = new EventCountView();
2571 v4->SetBounds(0, 0, 10, 10);
2572 internal::RootView* root_view =
2573 static_cast<internal::RootView*>(widget->GetRootView());
2574 root_view->AddChildView(v1);
2575 v1->AddChildView(v2);
2576 v2->AddChildView(v3);
2577 v3->AddChildView(v4);
2578
2579 widget->Show();
2580
2581 // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as
2582 // disabled.
2583 v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
2584 v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
2585 v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
2586 v3->SetEnabled(false);
2587
2588 // No gesture handler is set in the root view. In this case the tap event
2589 // should be dispatched only to |v4|, the gesture handler should be set to
2590 // |v3|, and the event should be marked as handled.
2591 GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5);
2592 widget->OnGestureEvent(&tap);
2593 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2594 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2595 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2596 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2597 EXPECT_EQ(v3, GetGestureHandler(root_view));
2598 EXPECT_TRUE(tap.handled());
2599 v1->ResetCounts();
2600 v2->ResetCounts();
2601 v3->ResetCounts();
2602 v4->ResetCounts();
2603
2604 // A subsequent gesture event should be marked as handled but not dispatched.
2605 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2606 widget->OnGestureEvent(&tap);
2607 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2608 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2609 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2610 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
2611 EXPECT_EQ(v3, GetGestureHandler(root_view));
2612 EXPECT_TRUE(tap.handled());
2613 v1->ResetCounts();
2614 v2->ResetCounts();
2615 v3->ResetCounts();
2616 v4->ResetCounts();
2617
2618 // A GESTURE_END should reset the default gesture handler to NULL. It should
2619 // also not be dispatched to |v3| but still marked as handled.
2620 GestureEventForTest end(ui::ET_GESTURE_END, 5, 5);
2621 widget->OnGestureEvent(&end);
2622 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2623 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2624 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2625 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2626 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2627 EXPECT_TRUE(end.handled());
2628 v1->ResetCounts();
2629 v2->ResetCounts();
2630 v3->ResetCounts();
2631 v4->ResetCounts();
2632
2633 // Change the handle mode of |v3| to indicate that it would no longer like
2634 // to handle events which are dispatched to it.
2635 v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
2636
2637 // No gesture handler is set in the root view. In this case the tap event
2638 // should be dispatched only to |v4| and the event should be marked as
2639 // handled. Furthermore, the gesture handler should be set to
2640 // |v3|; even though |v3| does not explicitly handle events, it is a
2641 // valid target for the tap event because it is disabled.
2642 tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5);
2643 widget->OnGestureEvent(&tap);
2644 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
2645 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
2646 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP));
2647 EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
2648 EXPECT_EQ(v3, GetGestureHandler(root_view));
2649 EXPECT_TRUE(tap.handled());
2650 v1->ResetCounts();
2651 v2->ResetCounts();
2652 v3->ResetCounts();
2653 v4->ResetCounts();
2654
2655 // A GESTURE_END should reset the default gesture handler to NULL. It should
2656 // also not be dispatched to |v3| but still marked as handled.
2657 end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5);
2658 widget->OnGestureEvent(&end);
2659 EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
2660 EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
2661 EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
2662 EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
2663 EXPECT_EQ(NULL, GetGestureHandler(root_view));
2664 EXPECT_TRUE(end.handled());
2665
2666 widget->Close();
2667 }
2668
2669 // Test the result of Widget::GetAllChildWidgets().
2670 TEST_F(WidgetTest, GetAllChildWidgets) {
2671 // Create the following widget hierarchy:
2672 //
2673 // toplevel
2674 // +-- w1
2675 // +-- w11
2676 // +-- w2
2677 // +-- w21
2678 // +-- w22
2679 Widget* toplevel = CreateTopLevelPlatformWidget();
2680 Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
2681 Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
2682 Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
2683 Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
2684 Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
2685
2686 std::set<Widget*> expected;
2687 expected.insert(toplevel);
2688 expected.insert(w1);
2689 expected.insert(w11);
2690 expected.insert(w2);
2691 expected.insert(w21);
2692 expected.insert(w22);
2693
2694 std::set<Widget*> widgets;
2695 Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
2696
2697 EXPECT_EQ(expected.size(), widgets.size());
2698 EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
2699 }
2700
2701 // Used by DestroyChildWidgetsInOrder. On destruction adds the supplied name to
2702 // a vector.
2703 class DestroyedTrackingView : public View {
2704 public:
2705 DestroyedTrackingView(const std::string& name,
2706 std::vector<std::string>* add_to)
2707 : name_(name),
2708 add_to_(add_to) {
2709 }
2710
2711 virtual ~DestroyedTrackingView() {
2712 add_to_->push_back(name_);
2713 }
2714
2715 private:
2716 const std::string name_;
2717 std::vector<std::string>* add_to_;
2718
2719 DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingView);
2720 };
2721
2722 class WidgetChildDestructionTest : public WidgetTest {
2723 public:
2724 WidgetChildDestructionTest() {}
2725
2726 // Creates a top level and a child, destroys the child and verifies the views
2727 // of the child are destroyed before the views of the parent.
2728 void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
2729 bool child_has_desktop_native_widget_aura) {
2730 // When a View is destroyed its name is added here.
2731 std::vector<std::string> destroyed;
2732
2733 Widget* top_level = new Widget;
2734 Widget::InitParams params =
2735 CreateParams(views::Widget::InitParams::TYPE_WINDOW);
2736 #if !defined(OS_CHROMEOS)
2737 if (top_level_has_desktop_native_widget_aura)
2738 params.native_widget = new PlatformDesktopNativeWidget(top_level);
2739 #endif
2740 top_level->Init(params);
2741 top_level->GetRootView()->AddChildView(
2742 new DestroyedTrackingView("parent", &destroyed));
2743 top_level->Show();
2744
2745 Widget* child = new Widget;
2746 Widget::InitParams child_params =
2747 CreateParams(views::Widget::InitParams::TYPE_POPUP);
2748 child_params.parent = top_level->GetNativeView();
2749 #if !defined(OS_CHROMEOS)
2750 if (child_has_desktop_native_widget_aura)
2751 child_params.native_widget = new PlatformDesktopNativeWidget(child);
2752 #endif
2753 child->Init(child_params);
2754 child->GetRootView()->AddChildView(
2755 new DestroyedTrackingView("child", &destroyed));
2756 child->Show();
2757
2758 // Should trigger destruction of the child too.
2759 top_level->native_widget_private()->CloseNow();
2760
2761 // Child should be destroyed first.
2762 ASSERT_EQ(2u, destroyed.size());
2763 EXPECT_EQ("child", destroyed[0]);
2764 EXPECT_EQ("parent", destroyed[1]);
2765 }
2766
2767 private:
2768 DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
2769 };
2770
2771 #if !defined(OS_CHROMEOS)
2772 // See description of RunDestroyChildWidgetsTest(). Parent uses
2773 // DesktopNativeWidgetAura.
2774 TEST_F(WidgetChildDestructionTest,
2775 DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
2776 RunDestroyChildWidgetsTest(true, false);
2777 }
2778
2779 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
2780 // DesktopNativeWidgetAura.
2781 TEST_F(WidgetChildDestructionTest,
2782 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
2783 RunDestroyChildWidgetsTest(true, true);
2784 }
2785 #endif // !defined(OS_CHROMEOS)
2786
2787 // See description of RunDestroyChildWidgetsTest().
2788 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
2789 RunDestroyChildWidgetsTest(false, false);
2790 }
2791
2792 #if !defined(OS_CHROMEOS)
2793 // Provides functionality to create a window modal dialog.
2794 class ModalDialogDelegate : public DialogDelegateView {
2795 public:
2796 ModalDialogDelegate() {}
2797 virtual ~ModalDialogDelegate() {}
2798
2799 // WidgetDelegate overrides.
2800 virtual ui::ModalType GetModalType() const override {
2801 return ui::MODAL_TYPE_WINDOW;
2802 }
2803
2804 private:
2805 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
2806 };
2807
2808 // This test verifies that whether mouse events when a modal dialog is
2809 // displayed are eaten or recieved by the dialog.
2810 TEST_F(WidgetTest, WindowMouseModalityTest) {
2811 // Create a top level widget.
2812 Widget top_level_widget;
2813 Widget::InitParams init_params =
2814 CreateParams(Widget::InitParams::TYPE_WINDOW);
2815 init_params.show_state = ui::SHOW_STATE_NORMAL;
2816 gfx::Rect initial_bounds(0, 0, 500, 500);
2817 init_params.bounds = initial_bounds;
2818 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2819 init_params.native_widget =
2820 new PlatformDesktopNativeWidget(&top_level_widget);
2821 top_level_widget.Init(init_params);
2822 top_level_widget.Show();
2823 EXPECT_TRUE(top_level_widget.IsVisible());
2824
2825 // Create a view and validate that a mouse moves makes it to the view.
2826 EventCountView* widget_view = new EventCountView();
2827 widget_view->SetBounds(0, 0, 10, 10);
2828 top_level_widget.GetRootView()->AddChildView(widget_view);
2829
2830 gfx::Point cursor_location_main(5, 5);
2831 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
2832 cursor_location_main,
2833 cursor_location_main,
2834 ui::EF_NONE,
2835 ui::EF_NONE);
2836 ui::EventDispatchDetails details =
2837 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
2838 ASSERT_FALSE(details.dispatcher_destroyed);
2839
2840 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
2841 widget_view->ResetCounts();
2842
2843 // Create a modal dialog and validate that a mouse down message makes it to
2844 // the main view within the dialog.
2845
2846 // This instance will be destroyed when the dialog is destroyed.
2847 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2848
2849 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2850 dialog_delegate, NULL, top_level_widget.GetNativeView());
2851 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2852 EventCountView* dialog_widget_view = new EventCountView();
2853 dialog_widget_view->SetBounds(0, 0, 50, 50);
2854 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
2855 modal_dialog_widget->Show();
2856 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2857
2858 gfx::Point cursor_location_dialog(100, 100);
2859 ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
2860 cursor_location_dialog,
2861 cursor_location_dialog,
2862 ui::EF_NONE,
2863 ui::EF_NONE);
2864 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2865 &mouse_down_dialog);
2866 ASSERT_FALSE(details.dispatcher_destroyed);
2867 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
2868
2869 // Send a mouse move message to the main window. It should not be received by
2870 // the main window as the modal dialog is still active.
2871 gfx::Point cursor_location_main2(6, 6);
2872 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
2873 cursor_location_main2,
2874 cursor_location_main2,
2875 ui::EF_NONE,
2876 ui::EF_NONE);
2877 details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
2878 &mouse_down_main);
2879 ASSERT_FALSE(details.dispatcher_destroyed);
2880 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
2881
2882 modal_dialog_widget->CloseNow();
2883 top_level_widget.CloseNow();
2884 }
2885
2886 // Verifies nativeview visbility matches that of Widget visibility when
2887 // SetFullscreen is invoked.
2888 TEST_F(WidgetTest, FullscreenStatePropagated) {
2889 Widget::InitParams init_params =
2890 CreateParams(Widget::InitParams::TYPE_WINDOW);
2891 init_params.show_state = ui::SHOW_STATE_NORMAL;
2892 init_params.bounds = gfx::Rect(0, 0, 500, 500);
2893 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2894
2895 {
2896 Widget top_level_widget;
2897 top_level_widget.Init(init_params);
2898 top_level_widget.SetFullscreen(true);
2899 EXPECT_EQ(top_level_widget.IsVisible(),
2900 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2901 top_level_widget.CloseNow();
2902 }
2903 #if !defined(OS_CHROMEOS)
2904 {
2905 Widget top_level_widget;
2906 init_params.native_widget =
2907 new PlatformDesktopNativeWidget(&top_level_widget);
2908 top_level_widget.Init(init_params);
2909 top_level_widget.SetFullscreen(true);
2910 EXPECT_EQ(top_level_widget.IsVisible(),
2911 IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
2912 top_level_widget.CloseNow();
2913 }
2914 #endif
2915 }
2916 #if defined(OS_WIN)
2917
2918 // Provides functionality to test widget activation via an activation flag
2919 // which can be set by an accessor.
2920 class ModalWindowTestWidgetDelegate : public WidgetDelegate {
2921 public:
2922 ModalWindowTestWidgetDelegate()
2923 : widget_(NULL),
2924 can_activate_(true) {}
2925
2926 virtual ~ModalWindowTestWidgetDelegate() {}
2927
2928 // Overridden from WidgetDelegate:
2929 virtual void DeleteDelegate() override {
2930 delete this;
2931 }
2932 virtual Widget* GetWidget() override {
2933 return widget_;
2934 }
2935 virtual const Widget* GetWidget() const override {
2936 return widget_;
2937 }
2938 virtual bool CanActivate() const override {
2939 return can_activate_;
2940 }
2941 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
2942 return true;
2943 }
2944
2945 void set_can_activate(bool can_activate) {
2946 can_activate_ = can_activate;
2947 }
2948
2949 void set_widget(Widget* widget) {
2950 widget_ = widget;
2951 }
2952
2953 private:
2954 Widget* widget_;
2955 bool can_activate_;
2956
2957 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate);
2958 };
2959
2960 // Tests whether we can activate the top level widget when a modal dialog is
2961 // active.
2962 TEST_F(WidgetTest, WindowModalityActivationTest) {
2963 // Destroyed when the top level widget created below is destroyed.
2964 ModalWindowTestWidgetDelegate* widget_delegate =
2965 new ModalWindowTestWidgetDelegate;
2966 // Create a top level widget.
2967 Widget top_level_widget;
2968 Widget::InitParams init_params =
2969 CreateParams(Widget::InitParams::TYPE_WINDOW);
2970 init_params.show_state = ui::SHOW_STATE_NORMAL;
2971 gfx::Rect initial_bounds(0, 0, 500, 500);
2972 init_params.bounds = initial_bounds;
2973 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2974 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
2975 init_params.delegate = widget_delegate;
2976 top_level_widget.Init(init_params);
2977 widget_delegate->set_widget(&top_level_widget);
2978 top_level_widget.Show();
2979 EXPECT_TRUE(top_level_widget.IsVisible());
2980
2981 HWND win32_window = views::HWNDForWidget(&top_level_widget);
2982 EXPECT_TRUE(::IsWindow(win32_window));
2983
2984 // This instance will be destroyed when the dialog is destroyed.
2985 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
2986
2987 // We should be able to activate the window even if the WidgetDelegate
2988 // says no, when a modal dialog is active.
2989 widget_delegate->set_can_activate(false);
2990
2991 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
2992 dialog_delegate, NULL, top_level_widget.GetNativeWindow());
2993 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
2994 modal_dialog_widget->Show();
2995 EXPECT_TRUE(modal_dialog_widget->IsVisible());
2996
2997 LRESULT activate_result = ::SendMessage(
2998 win32_window,
2999 WM_MOUSEACTIVATE,
3000 reinterpret_cast<WPARAM>(win32_window),
3001 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
3002 EXPECT_EQ(activate_result, MA_ACTIVATE);
3003
3004 modal_dialog_widget->CloseNow();
3005 top_level_widget.CloseNow();
3006 }
3007 #endif // defined(OS_WIN)
3008 #endif // !defined(OS_CHROMEOS)
3009
3010 TEST_F(WidgetTest, ShowCreatesActiveWindow) {
3011 Widget* widget = CreateTopLevelPlatformWidget();
3012
3013 widget->Show();
3014 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3015
3016 widget->CloseNow();
3017 }
3018
3019 // OSX does not have a per-application "active" window such as provided by
3020 // ::GetActiveWindow() on Windows. There is only a system-wide "keyWindow" which
3021 // is updated asynchronously.
3022 #if defined(OS_MACOSX)
3023 #define MAYBE_ShowInactive DISABLED_ShowInactive
3024 #else
3025 #define MAYBE_ShowInactive ShowInactive
3026 #endif
3027 TEST_F(WidgetTest, MAYBE_ShowInactive) {
3028 Widget* widget = CreateTopLevelPlatformWidget();
3029
3030 widget->ShowInactive();
3031 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
3032
3033 widget->CloseNow();
3034 }
3035
3036 TEST_F(WidgetTest, InactiveBeforeShow) {
3037 Widget* widget = CreateTopLevelPlatformWidget();
3038
3039 EXPECT_FALSE(widget->IsActive());
3040 EXPECT_FALSE(widget->IsVisible());
3041
3042 widget->Show();
3043
3044 EXPECT_TRUE(widget->IsActive());
3045 EXPECT_TRUE(widget->IsVisible());
3046
3047 widget->CloseNow();
3048 }
3049
3050 TEST_F(WidgetTest, ShowInactiveAfterShow) {
3051 // Create 2 widgets to ensure window layering does not change.
3052 Widget* widget = CreateTopLevelPlatformWidget();
3053 Widget* widget2 = CreateTopLevelPlatformWidget();
3054
3055 widget2->Show();
3056 EXPECT_FALSE(widget->IsActive());
3057 EXPECT_TRUE(widget2->IsVisible());
3058 EXPECT_TRUE(widget2->IsActive());
3059
3060 widget->Show();
3061 EXPECT_TRUE(widget->IsActive());
3062 EXPECT_FALSE(widget2->IsActive());
3063 widget->ShowInactive();
3064 EXPECT_TRUE(widget->IsActive());
3065 EXPECT_FALSE(widget2->IsActive());
3066 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3067
3068 widget2->CloseNow();
3069 widget->CloseNow();
3070 }
3071
3072 TEST_F(WidgetTest, ShowAfterShowInactive) {
3073 Widget* widget = CreateTopLevelPlatformWidget();
3074
3075 widget->ShowInactive();
3076 widget->Show();
3077 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3078
3079 widget->CloseNow();
3080 }
3081
3082 #if !defined(OS_CHROMEOS)
3083 TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
3084 Widget* widget = CreateTopLevelPlatformWidget();
3085 widget->Show();
3086 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3087
3088 Widget widget2;
3089 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3090 params.native_widget = new PlatformDesktopNativeWidget(&widget2);
3091 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3092 widget2.Init(params);
3093 widget2.Show();
3094
3095 EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
3096 EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
3097
3098 widget->CloseNow();
3099 widget2.CloseNow();
3100 }
3101 #endif // !defined(OS_CHROMEOS)
3102
3103 namespace {
3104
3105 class FullscreenAwareFrame : public views::NonClientFrameView {
3106 public:
3107 explicit FullscreenAwareFrame(views::Widget* widget)
3108 : widget_(widget), fullscreen_layout_called_(false) {}
3109 virtual ~FullscreenAwareFrame() {}
3110
3111 // views::NonClientFrameView overrides:
3112 virtual gfx::Rect GetBoundsForClientView() const override {
3113 return gfx::Rect();
3114 }
3115 virtual gfx::Rect GetWindowBoundsForClientBounds(
3116 const gfx::Rect& client_bounds) const override {
3117 return gfx::Rect();
3118 }
3119 virtual int NonClientHitTest(const gfx::Point& point) override {
3120 return HTNOWHERE;
3121 }
3122 virtual void GetWindowMask(const gfx::Size& size,
3123 gfx::Path* window_mask) override {}
3124 virtual void ResetWindowControls() override {}
3125 virtual void UpdateWindowIcon() override {}
3126 virtual void UpdateWindowTitle() override {}
3127 virtual void SizeConstraintsChanged() override {}
3128
3129 // views::View overrides:
3130 virtual void Layout() override {
3131 if (widget_->IsFullscreen())
3132 fullscreen_layout_called_ = true;
3133 }
3134
3135 bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
3136
3137 private:
3138 views::Widget* widget_;
3139 bool fullscreen_layout_called_;
3140
3141 DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
3142 };
3143
3144 } // namespace
3145
3146 // Tests that frame Layout is called when a widget goes fullscreen without
3147 // changing its size or title.
3148 TEST_F(WidgetTest, FullscreenFrameLayout) {
3149 Widget* widget = CreateTopLevelPlatformWidget();
3150 FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
3151 widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
3152
3153 widget->Maximize();
3154 RunPendingMessages();
3155
3156 EXPECT_FALSE(frame->fullscreen_layout_called());
3157 widget->SetFullscreen(true);
3158 widget->Show();
3159 RunPendingMessages();
3160 EXPECT_TRUE(frame->fullscreen_layout_called());
3161
3162 widget->CloseNow();
3163 }
3164
3165 #if !defined(OS_CHROMEOS)
3166 namespace {
3167
3168 // Trivial WidgetObserverTest that invokes Widget::IsActive() from
3169 // OnWindowDestroying.
3170 class IsActiveFromDestroyObserver : public WidgetObserver {
3171 public:
3172 IsActiveFromDestroyObserver() {}
3173 virtual ~IsActiveFromDestroyObserver() {}
3174 virtual void OnWidgetDestroying(Widget* widget) override {
3175 widget->IsActive();
3176 }
3177
3178 private:
3179 DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
3180 };
3181
3182 } // namespace
3183
3184 // Verifies Widget::IsActive() invoked from
3185 // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
3186 TEST_F(WidgetTest, IsActiveFromDestroy) {
3187 // Create two widgets, one a child of the other.
3188 IsActiveFromDestroyObserver observer;
3189 Widget parent_widget;
3190 Widget::InitParams parent_params =
3191 CreateParams(Widget::InitParams::TYPE_POPUP);
3192 parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
3193 parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3194 parent_widget.Init(parent_params);
3195 parent_widget.Show();
3196
3197 Widget child_widget;
3198 Widget::InitParams child_params =
3199 CreateParams(Widget::InitParams::TYPE_POPUP);
3200 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3201 child_params.context = parent_widget.GetNativeWindow();
3202 child_widget.Init(child_params);
3203 child_widget.AddObserver(&observer);
3204 child_widget.Show();
3205
3206 parent_widget.CloseNow();
3207 }
3208 #endif // !defined(OS_CHROMEOS)
3209
3210 // Tests that events propagate through from the dispatcher with the correct
3211 // event type, and that the different platforms behave the same.
3212 TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
3213 EventCountView* view = new EventCountView;
3214 view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3215 view->SetBounds(10, 10, 50, 40);
3216
3217 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3218 widget->GetRootView()->AddChildView(view);
3219
3220 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3221 widget->Show();
3222
3223 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3224 generator.set_current_location(gfx::Point(20, 20));
3225
3226 generator.ClickLeftButton();
3227 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3228 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3229 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3230
3231 generator.PressRightButton();
3232 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3233 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3234 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3235
3236 generator.ReleaseRightButton();
3237 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3238 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3239 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
3240
3241 // Test mouse move events.
3242 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
3243 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3244
3245 // Move the mouse within the view (20, 20) -> (30, 30).
3246 generator.MoveMouseTo(gfx::Point(30, 30));
3247 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
3248 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3249 EXPECT_EQ(ui::EF_NONE, view->last_flags());
3250
3251 // Move it again - entered count shouldn't change.
3252 generator.MoveMouseTo(gfx::Point(31, 31));
3253 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3254 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3255 EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
3256
3257 // Move it off the view.
3258 generator.MoveMouseTo(gfx::Point(5, 5));
3259 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
3260 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3261 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3262
3263 // Move it back on.
3264 generator.MoveMouseTo(gfx::Point(20, 20));
3265 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
3266 EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
3267 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
3268
3269 // Drargging. Cover HasCapture() and NativeWidgetPrivate::IsMouseButtonDown().
3270 generator.DragMouseTo(gfx::Point(40, 40));
3271 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
3272 EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
3273 EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3274 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
3275
3276 widget->CloseNow();
3277 }
3278
3279 // Tests that a view does not receive entered, dragged, or moved events if
3280 // a mouse cursor is moved into it while the left mouse button is pressed.
3281 TEST_F(WidgetTest, DragIntoView) {
3282 EventCountView* container = new EventCountView;
3283 container->SetBounds(0, 0, 100, 80);
3284
3285 EventCountView* consume_view = new EventCountView;
3286 consume_view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3287 consume_view->SetBounds(10, 10, 50, 40);
3288
3289 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3290 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3291 widget->SetContentsView(container);
3292 container->AddChildView(consume_view);
3293
3294 widget->Show();
3295
3296 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3297 generator.set_current_location(gfx::Point(75, 15));
3298
3299 generator.PressLeftButton();
3300 generator.MoveMouseTo(gfx::Point(20, 20));
3301 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_ENTERED));
3302 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3303 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_MOVED));
3304
3305 widget->CloseNow();
3306 }
3307
3308 // Tests that a view receives the correct mouse events if a mouse cursor
3309 // is moved out of its bounds while the left mouse button is pressed.
3310 TEST_F(WidgetTest, DragOutOfView) {
3311 EventCountView* container = new EventCountView;
3312 container->SetBounds(0, 0, 100, 80);
3313
3314 EventCountView* consume_view = new EventCountView;
3315 consume_view->set_handle_mode(EventCountView::CONSUME_EVENTS);
3316 consume_view->SetBounds(10, 10, 50, 40);
3317
3318 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3319 widget->SetBounds(gfx::Rect(0, 0, 100, 80));
3320 widget->SetContentsView(container);
3321 container->AddChildView(consume_view);
3322
3323 widget->Show();
3324
3325 ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
3326 generator.set_current_location(gfx::Point(20, 20));
3327
3328 generator.PressLeftButton();
3329 EXPECT_EQ(1, consume_view->GetEventCount(ui::ET_MOUSE_PRESSED));
3330 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_PRESSED));
3331 consume_view->ResetCounts();
3332
3333 generator.MoveMouseTo(gfx::Point(70, 70));
3334 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_EXITED));
3335 EXPECT_EQ(1, consume_view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3336 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_MOVED));
3337 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_ENTERED));
3338 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_DRAGGED));
3339 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_MOVED));
3340 consume_view->ResetCounts();
3341
3342 generator.MoveMouseTo(gfx::Point(71, 71));
3343 EXPECT_EQ(1, consume_view->GetEventCount(ui::ET_MOUSE_DRAGGED));
3344 EXPECT_EQ(0, consume_view->GetEventCount(ui::ET_MOUSE_MOVED));
3345 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_DRAGGED));
3346 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_MOVED));
3347 consume_view->ResetCounts();
3348
3349 generator.ReleaseLeftButton();
3350 EXPECT_EQ(1, consume_view->GetEventCount(ui::ET_MOUSE_RELEASED));
3351 EXPECT_EQ(0, container->GetEventCount(ui::ET_MOUSE_RELEASED));
3352 consume_view->ResetCounts();
3353
3354 widget->CloseNow();
3355 }
3356
3357 // Tests that the root view is correctly set up for Widget types that do not
3358 // require a non-client view, before any other views are added to the widget.
3359 // That is, before Widget::ReorderNativeViews() is called which, if called with
3360 // a root view not set, could cause the root view to get resized to the widget.
3361 TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
3362 Widget* widget = CreateTopLevelFramelessPlatformWidget();
3363 View* root_view = widget->GetRootView();
3364
3365 // Size the root view to exceed the widget bounds.
3366 const gfx::Rect test_rect(0, 0, 500, 500);
3367 root_view->SetBoundsRect(test_rect);
3368
3369 EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
3370
3371 EXPECT_EQ(test_rect, root_view->bounds());
3372 widget->ReorderNativeViews();
3373 EXPECT_EQ(test_rect, root_view->bounds());
3374
3375 widget->CloseNow();
3376 }
3377
3378 } // namespace test
3379 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/widget_removals_observer.h ('k') | ui/views/widget/window_reorderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698