Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / widget_interactive_uitest.cc
1 // Copyright (c) 2013 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 "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/command_line.h"
8 #include "base/path_service.h"
9 #include "base/run_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/base/ui_base_paths.h"
14 #include "ui/base/ui_base_switches.h"
15 #include "ui/events/event_processor.h"
16 #include "ui/events/test/event_generator.h"
17 #include "ui/gfx/native_widget_types.h"
18 #include "ui/gl/gl_surface.h"
19 #include "ui/views/controls/textfield/textfield.h"
20 #include "ui/views/controls/textfield/textfield_test_api.h"
21 #include "ui/views/focus/focus_manager.h"
22 #include "ui/views/test/focus_manager_test.h"
23 #include "ui/views/test/widget_test.h"
24 #include "ui/views/touchui/touch_selection_controller_impl.h"
25 #include "ui/views/widget/widget.h"
26 #include "ui/views/window/dialog_delegate.h"
27 #include "ui/wm/public/activation_client.h"
28
29 #if defined(OS_WIN)
30 #include "ui/aura/window.h"
31 #include "ui/aura/window_tree_host.h"
32 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
33 #include "ui/views/win/hwnd_util.h"
34 #endif
35
36 namespace views {
37 namespace test {
38
39 namespace {
40
41 // A View that closes the Widget and exits the current message-loop when it
42 // receives a mouse-release event.
43 class ExitLoopOnRelease : public View {
44  public:
45   ExitLoopOnRelease() {}
46   virtual ~ExitLoopOnRelease() {}
47
48  private:
49   // Overridden from View:
50   virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
51     GetWidget()->Close();
52     base::MessageLoop::current()->QuitNow();
53   }
54
55   DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease);
56 };
57
58 // A view that does a capture on ui::ET_GESTURE_TAP_DOWN events.
59 class GestureCaptureView : public View {
60  public:
61   GestureCaptureView() {}
62   virtual ~GestureCaptureView() {}
63
64  private:
65   // Overridden from View:
66   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
67     if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
68       GetWidget()->SetCapture(this);
69       event->StopPropagation();
70     }
71   }
72
73   DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
74 };
75
76 // A view that always processes all mouse events.
77 class MouseView : public View {
78  public:
79   MouseView()
80       : View(),
81         entered_(0),
82         exited_(0),
83         pressed_(0) {
84   }
85   virtual ~MouseView() {}
86
87   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
88     pressed_++;
89     return true;
90   }
91
92   virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
93     entered_++;
94   }
95
96   virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
97     exited_++;
98   }
99
100   // Return the number of OnMouseEntered calls and reset the counter.
101   int EnteredCalls() {
102     int i = entered_;
103     entered_ = 0;
104     return i;
105   }
106
107   // Return the number of OnMouseExited calls and reset the counter.
108   int ExitedCalls() {
109     int i = exited_;
110     exited_ = 0;
111     return i;
112   }
113
114   int pressed() const { return pressed_; }
115
116  private:
117   int entered_;
118   int exited_;
119
120   int pressed_;
121
122   DISALLOW_COPY_AND_ASSIGN(MouseView);
123 };
124
125 // A View that shows a different widget, sets capture on that widget, and
126 // initiates a nested message-loop when it receives a mouse-press event.
127 class NestedLoopCaptureView : public View {
128  public:
129   explicit NestedLoopCaptureView(Widget* widget) : widget_(widget) {}
130   virtual ~NestedLoopCaptureView() {}
131
132  private:
133   // Overridden from View:
134   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
135     // Start a nested loop.
136     widget_->Show();
137     widget_->SetCapture(widget_->GetContentsView());
138     EXPECT_TRUE(widget_->HasCapture());
139
140     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
141     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
142
143     base::RunLoop run_loop;
144     run_loop.Run();
145     return true;
146   }
147
148   Widget* widget_;
149
150   DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView);
151 };
152
153 }  // namespace
154
155 class WidgetTestInteractive : public WidgetTest {
156  public:
157   WidgetTestInteractive() {}
158   virtual ~WidgetTestInteractive() {}
159
160   virtual void SetUp() OVERRIDE {
161     gfx::GLSurface::InitializeOneOffForTests();
162     ui::RegisterPathProvider();
163     base::FilePath ui_test_pak_path;
164     ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
165     ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
166     WidgetTest::SetUp();
167   }
168
169  protected:
170   static void ShowQuickMenuImmediately(
171       TouchSelectionControllerImpl* controller) {
172     DCHECK(controller);
173     if (controller->context_menu_timer_.IsRunning()) {
174       controller->context_menu_timer_.Stop();
175 // TODO(tapted): Enable this when porting ui/views/touchui to Mac.
176 #if !defined(OS_MACOSX)
177       controller->ContextMenuTimerFired();
178 #endif
179     }
180   }
181
182   static bool IsQuickMenuVisible(TouchSelectionControllerImpl* controller) {
183     DCHECK(controller);
184     return controller->context_menu_ && controller->context_menu_->visible();
185   }
186 };
187
188 #if defined(OS_WIN)
189 // Tests whether activation and focus change works correctly in Windows.
190 // We test the following:-
191 // 1. If the active aura window is correctly set when a top level widget is
192 //    created.
193 // 2. If the active aura window in widget 1 created above, is set to NULL when
194 //    another top level widget is created and focused.
195 // 3. On focusing the native platform window for widget 1, the active aura
196 //    window for widget 1 should be set and that for widget 2 should reset.
197 // TODO(ananta): Discuss with erg on how to write this test for linux x11 aura.
198 TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) {
199   // Create widget 1 and expect the active window to be its window.
200   View* contents_view1 = new View;
201   contents_view1->SetFocusable(true);
202   Widget widget1;
203   Widget::InitParams init_params =
204       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
205   init_params.bounds = gfx::Rect(0, 0, 200, 200);
206   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
207   init_params.native_widget = new DesktopNativeWidgetAura(&widget1);
208   widget1.Init(init_params);
209   widget1.SetContentsView(contents_view1);
210   widget1.Show();
211   aura::Window* root_window1= widget1.GetNativeView()->GetRootWindow();
212   contents_view1->RequestFocus();
213
214   EXPECT_TRUE(root_window1 != NULL);
215   aura::client::ActivationClient* activation_client1 =
216       aura::client::GetActivationClient(root_window1);
217   EXPECT_TRUE(activation_client1 != NULL);
218   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
219
220   // Create widget 2 and expect the active window to be its window.
221   View* contents_view2 = new View;
222   Widget widget2;
223   Widget::InitParams init_params2 =
224       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
225   init_params2.bounds = gfx::Rect(0, 0, 200, 200);
226   init_params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
227   init_params2.native_widget = new DesktopNativeWidgetAura(&widget2);
228   widget2.Init(init_params2);
229   widget2.SetContentsView(contents_view2);
230   widget2.Show();
231   aura::Window* root_window2 = widget2.GetNativeView()->GetRootWindow();
232   contents_view2->RequestFocus();
233   ::SetActiveWindow(
234       root_window2->GetHost()->GetAcceleratedWidget());
235
236   aura::client::ActivationClient* activation_client2 =
237       aura::client::GetActivationClient(root_window2);
238   EXPECT_TRUE(activation_client2 != NULL);
239   EXPECT_EQ(activation_client2->GetActiveWindow(), widget2.GetNativeView());
240   EXPECT_EQ(activation_client1->GetActiveWindow(),
241             reinterpret_cast<aura::Window*>(NULL));
242
243   // Now set focus back to widget 1 and expect the active window to be its
244   // window.
245   contents_view1->RequestFocus();
246   ::SetActiveWindow(
247       root_window1->GetHost()->GetAcceleratedWidget());
248   EXPECT_EQ(activation_client2->GetActiveWindow(),
249             reinterpret_cast<aura::Window*>(NULL));
250   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
251 }
252 #endif  // defined(OS_WIN)
253
254 TEST_F(WidgetTestInteractive, CaptureAutoReset) {
255   Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
256   View* container = new View;
257   toplevel->SetContentsView(container);
258
259   EXPECT_FALSE(toplevel->HasCapture());
260   toplevel->SetCapture(NULL);
261   EXPECT_TRUE(toplevel->HasCapture());
262
263   // By default, mouse release removes capture.
264   gfx::Point click_location(45, 15);
265   ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
266                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
267   toplevel->OnMouseEvent(&release);
268   EXPECT_FALSE(toplevel->HasCapture());
269
270   // Now a mouse release shouldn't remove capture.
271   toplevel->set_auto_release_capture(false);
272   toplevel->SetCapture(NULL);
273   EXPECT_TRUE(toplevel->HasCapture());
274   toplevel->OnMouseEvent(&release);
275   EXPECT_TRUE(toplevel->HasCapture());
276   toplevel->ReleaseCapture();
277   EXPECT_FALSE(toplevel->HasCapture());
278
279   toplevel->Close();
280   RunPendingMessages();
281 }
282
283 TEST_F(WidgetTestInteractive, ResetCaptureOnGestureEnd) {
284   Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
285   View* container = new View;
286   toplevel->SetContentsView(container);
287
288   View* gesture = new GestureCaptureView;
289   gesture->SetBounds(0, 0, 30, 30);
290   container->AddChildView(gesture);
291
292   MouseView* mouse = new MouseView;
293   mouse->SetBounds(30, 0, 30, 30);
294   container->AddChildView(mouse);
295
296   toplevel->SetSize(gfx::Size(100, 100));
297   toplevel->Show();
298
299   // Start a gesture on |gesture|.
300   ui::GestureEvent tap_down(15,
301                             15,
302                             0,
303                             base::TimeDelta(),
304                             ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
305   ui::GestureEvent end(15,
306                        15,
307                        0,
308                        base::TimeDelta(),
309                        ui::GestureEventDetails(ui::ET_GESTURE_END));
310   toplevel->OnGestureEvent(&tap_down);
311
312   // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
313   // will not receive the event.
314   gfx::Point click_location(45, 15);
315
316   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
317                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
318   ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
319                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
320
321   EXPECT_TRUE(toplevel->HasCapture());
322
323   toplevel->OnMouseEvent(&press);
324   toplevel->OnMouseEvent(&release);
325   EXPECT_EQ(0, mouse->pressed());
326
327   EXPECT_FALSE(toplevel->HasCapture());
328
329   // The end of the gesture should release the capture, and pressing on |mouse|
330   // should now reach |mouse|.
331   toplevel->OnGestureEvent(&end);
332   toplevel->OnMouseEvent(&press);
333   toplevel->OnMouseEvent(&release);
334   EXPECT_EQ(1, mouse->pressed());
335
336   toplevel->Close();
337   RunPendingMessages();
338 }
339
340 // Checks that if a mouse-press triggers a capture on a different widget (which
341 // consumes the mouse-release event), then the target of the press does not have
342 // capture.
343 TEST_F(WidgetTestInteractive, DisableCaptureWidgetFromMousePress) {
344   // The test creates two widgets: |first| and |second|.
345   // The View in |first| makes |second| visible, sets capture on it, and starts
346   // a nested loop (like a menu does). The View in |second| terminates the
347   // nested loop and closes the widget.
348   // The test sends a mouse-press event to |first|, and posts a task to send a
349   // release event to |second|, to make sure that the release event is
350   // dispatched after the nested loop starts.
351
352   Widget* first = CreateTopLevelFramelessPlatformWidget();
353   Widget* second = CreateTopLevelFramelessPlatformWidget();
354
355   View* container = new NestedLoopCaptureView(second);
356   first->SetContentsView(container);
357
358   second->SetContentsView(new ExitLoopOnRelease());
359
360   first->SetSize(gfx::Size(100, 100));
361   first->Show();
362
363   gfx::Point location(20, 20);
364   base::MessageLoop::current()->PostTask(FROM_HERE,
365       base::Bind(&Widget::OnMouseEvent,
366                  base::Unretained(second),
367                  base::Owned(new ui::MouseEvent(ui::ET_MOUSE_RELEASED,
368                                                 location,
369                                                 location,
370                                                 ui::EF_LEFT_MOUSE_BUTTON,
371                                                 ui::EF_LEFT_MOUSE_BUTTON))));
372   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
373                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
374   first->OnMouseEvent(&press);
375   EXPECT_FALSE(first->HasCapture());
376   first->Close();
377   RunPendingMessages();
378 }
379
380 // Tests some grab/ungrab events.
381 // TODO(estade): can this be enabled now that this is an interactive ui test?
382 TEST_F(WidgetTestInteractive, DISABLED_GrabUngrab) {
383   Widget* toplevel = CreateTopLevelPlatformWidget();
384   Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
385   Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
386
387   toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
388
389   child1->SetBounds(gfx::Rect(10, 10, 300, 300));
390   View* view = new MouseView();
391   view->SetBounds(0, 0, 300, 300);
392   child1->GetRootView()->AddChildView(view);
393
394   child2->SetBounds(gfx::Rect(200, 10, 200, 200));
395   view = new MouseView();
396   view->SetBounds(0, 0, 200, 200);
397   child2->GetRootView()->AddChildView(view);
398
399   toplevel->Show();
400   RunPendingMessages();
401
402   // Click on child1
403   gfx::Point p1(45, 45);
404   ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
405                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
406   toplevel->OnMouseEvent(&pressed);
407
408   EXPECT_TRUE(toplevel->HasCapture());
409   EXPECT_TRUE(child1->HasCapture());
410   EXPECT_FALSE(child2->HasCapture());
411
412   ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
413                           ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
414   toplevel->OnMouseEvent(&released);
415
416   EXPECT_FALSE(toplevel->HasCapture());
417   EXPECT_FALSE(child1->HasCapture());
418   EXPECT_FALSE(child2->HasCapture());
419
420   RunPendingMessages();
421
422   // Click on child2
423   gfx::Point p2(315, 45);
424   ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
425                           ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
426   toplevel->OnMouseEvent(&pressed2);
427   EXPECT_TRUE(pressed2.handled());
428   EXPECT_TRUE(toplevel->HasCapture());
429   EXPECT_TRUE(child2->HasCapture());
430   EXPECT_FALSE(child1->HasCapture());
431
432   ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
433                            ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
434   toplevel->OnMouseEvent(&released2);
435   EXPECT_FALSE(toplevel->HasCapture());
436   EXPECT_FALSE(child1->HasCapture());
437   EXPECT_FALSE(child2->HasCapture());
438
439   toplevel->CloseNow();
440 }
441
442 // Tests mouse move outside of the window into the "resize controller" and back
443 // will still generate an OnMouseEntered and OnMouseExited event..
444 TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
445   Widget* toplevel = CreateTopLevelPlatformWidget();
446
447   toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
448
449   MouseView* view = new MouseView();
450   view->SetBounds(90, 90, 10, 10);
451   toplevel->GetRootView()->AddChildView(view);
452
453   toplevel->Show();
454   RunPendingMessages();
455
456   // Move to an outside position.
457   gfx::Point p1(200, 200);
458   ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE,
459                            ui::EF_NONE);
460   toplevel->OnMouseEvent(&moved_out);
461   EXPECT_EQ(0, view->EnteredCalls());
462   EXPECT_EQ(0, view->ExitedCalls());
463
464   // Move onto the active view.
465   gfx::Point p2(95, 95);
466   ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE,
467                             ui::EF_NONE);
468   toplevel->OnMouseEvent(&moved_over);
469   EXPECT_EQ(1, view->EnteredCalls());
470   EXPECT_EQ(0, view->ExitedCalls());
471
472   // Move onto the outer resizing border.
473   gfx::Point p3(102, 95);
474   ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE,
475                                ui::EF_NONE);
476   toplevel->OnMouseEvent(&moved_resizer);
477   EXPECT_EQ(0, view->EnteredCalls());
478   EXPECT_EQ(1, view->ExitedCalls());
479
480   // Move onto the view again.
481   toplevel->OnMouseEvent(&moved_over);
482   EXPECT_EQ(1, view->EnteredCalls());
483   EXPECT_EQ(0, view->ExitedCalls());
484
485   RunPendingMessages();
486
487   toplevel->CloseNow();
488 }
489
490 // Test view focus restoration when a widget is deactivated and re-activated.
491 TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
492   Widget* widget1 = CreateTopLevelPlatformWidget();
493   View* view1 = new View;
494   view1->SetFocusable(true);
495   widget1->GetContentsView()->AddChildView(view1);
496
497   Widget* widget2 = CreateTopLevelPlatformWidget();
498   View* view2a = new View;
499   View* view2b = new View;
500   view2a->SetFocusable(true);
501   view2b->SetFocusable(true);
502   widget2->GetContentsView()->AddChildView(view2a);
503   widget2->GetContentsView()->AddChildView(view2b);
504
505   widget1->Show();
506   EXPECT_TRUE(widget1->IsActive());
507   view1->RequestFocus();
508   EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
509
510   widget2->Show();
511   EXPECT_TRUE(widget2->IsActive());
512   EXPECT_FALSE(widget1->IsActive());
513   EXPECT_EQ(NULL, widget1->GetFocusManager()->GetFocusedView());
514   view2a->RequestFocus();
515   EXPECT_EQ(view2a, widget2->GetFocusManager()->GetFocusedView());
516   view2b->RequestFocus();
517   EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
518
519   widget1->Activate();
520   EXPECT_TRUE(widget1->IsActive());
521   EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
522   EXPECT_FALSE(widget2->IsActive());
523   EXPECT_EQ(NULL, widget2->GetFocusManager()->GetFocusedView());
524
525   widget2->Activate();
526   EXPECT_TRUE(widget2->IsActive());
527   EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
528   EXPECT_FALSE(widget1->IsActive());
529   EXPECT_EQ(NULL, widget1->GetFocusManager()->GetFocusedView());
530
531   widget1->CloseNow();
532   widget2->CloseNow();
533 }
534
535 #if defined(OS_WIN)
536
537 // Test view focus retention when a widget's HWND is disabled and re-enabled.
538 TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
539   Widget* widget = CreateTopLevelFramelessPlatformWidget();
540   widget->SetContentsView(new View);
541   for (size_t i = 0; i < 2; ++i) {
542     widget->GetContentsView()->AddChildView(new View);
543     widget->GetContentsView()->child_at(i)->SetFocusable(true);
544   }
545
546   widget->Show();
547   const HWND hwnd = HWNDForWidget(widget);
548   EXPECT_TRUE(::IsWindow(hwnd));
549   EXPECT_TRUE(::IsWindowEnabled(hwnd));
550   EXPECT_EQ(hwnd, ::GetActiveWindow());
551
552   for (int i = 0; i < widget->GetContentsView()->child_count(); ++i) {
553     SCOPED_TRACE(base::StringPrintf("Child view %d", i));
554     View* view = widget->GetContentsView()->child_at(i);
555
556     view->RequestFocus();
557     EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
558     EXPECT_FALSE(::EnableWindow(hwnd, FALSE));
559     EXPECT_FALSE(::IsWindowEnabled(hwnd));
560
561     // Oddly, disabling the HWND leaves it active with the focus unchanged.
562     EXPECT_EQ(hwnd, ::GetActiveWindow());
563     EXPECT_TRUE(widget->IsActive());
564     EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
565
566     EXPECT_TRUE(::EnableWindow(hwnd, TRUE));
567     EXPECT_TRUE(::IsWindowEnabled(hwnd));
568     EXPECT_EQ(hwnd, ::GetActiveWindow());
569     EXPECT_TRUE(widget->IsActive());
570     EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
571   }
572
573   widget->CloseNow();
574 }
575
576 // This class subclasses the Widget class to listen for activation change
577 // notifications and provides accessors to return information as to whether
578 // the widget is active. We need this to ensure that users of the widget
579 // class activate the widget only when the underlying window becomes really
580 // active. Previously we would activate the widget in the WM_NCACTIVATE
581 // message which is incorrect because APIs like FlashWindowEx flash the
582 // window caption by sending fake WM_NCACTIVATE messages.
583 class WidgetActivationTest : public Widget {
584  public:
585   WidgetActivationTest()
586       : active_(false) {}
587
588   virtual ~WidgetActivationTest() {}
589
590   virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE {
591     active_ = active;
592   }
593
594   bool active() const { return active_; }
595
596  private:
597   bool active_;
598
599   DISALLOW_COPY_AND_ASSIGN(WidgetActivationTest);
600 };
601
602 // Tests whether the widget only becomes active when the underlying window
603 // is really active.
604 TEST_F(WidgetTestInteractive, WidgetNotActivatedOnFakeActivationMessages) {
605   WidgetActivationTest widget1;
606   Widget::InitParams init_params =
607       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
608   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
609   init_params.native_widget = new DesktopNativeWidgetAura(&widget1);
610   init_params.bounds = gfx::Rect(0, 0, 200, 200);
611   widget1.Init(init_params);
612   widget1.Show();
613   EXPECT_EQ(true, widget1.active());
614
615   WidgetActivationTest widget2;
616   init_params.native_widget = new DesktopNativeWidgetAura(&widget2);
617   widget2.Init(init_params);
618   widget2.Show();
619   EXPECT_EQ(true, widget2.active());
620   EXPECT_EQ(false, widget1.active());
621
622   HWND win32_native_window1 = HWNDForWidget(&widget1);
623   EXPECT_TRUE(::IsWindow(win32_native_window1));
624
625   ::SendMessage(win32_native_window1, WM_NCACTIVATE, 1, 0);
626   EXPECT_EQ(false, widget1.active());
627   EXPECT_EQ(true, widget2.active());
628
629   ::SetActiveWindow(win32_native_window1);
630   EXPECT_EQ(true, widget1.active());
631   EXPECT_EQ(false, widget2.active());
632 }
633 #endif  // defined(OS_WIN)
634
635 #if !defined(OS_CHROMEOS)
636 // Provides functionality to create a window modal dialog.
637 class ModalDialogDelegate : public DialogDelegateView {
638  public:
639   explicit ModalDialogDelegate(ui::ModalType type) : type_(type) {}
640   virtual ~ModalDialogDelegate() {}
641
642   // WidgetDelegate overrides.
643   virtual ui::ModalType GetModalType() const OVERRIDE {
644     return type_;
645   }
646
647  private:
648   ui::ModalType type_;
649
650   DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
651 };
652
653 // Tests whether the focused window is set correctly when a modal window is
654 // created and destroyed. When it is destroyed it should focus the owner window.
655 TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
656   TestWidgetFocusChangeListener focus_listener;
657   WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
658   const std::vector<NativeViewPair>& focus_changes =
659       focus_listener.focus_changes();
660
661   // Create a top level widget.
662   Widget top_level_widget;
663   Widget::InitParams init_params =
664       CreateParams(Widget::InitParams::TYPE_WINDOW);
665   init_params.show_state = ui::SHOW_STATE_NORMAL;
666   gfx::Rect initial_bounds(0, 0, 500, 500);
667   init_params.bounds = initial_bounds;
668   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
669   init_params.native_widget =
670       new PlatformDesktopNativeWidget(&top_level_widget);
671   top_level_widget.Init(init_params);
672   top_level_widget.Show();
673
674   gfx::NativeView top_level_native_view = top_level_widget.GetNativeView();
675   EXPECT_EQ(1u, focus_changes.size());
676   EXPECT_EQ(NativeViewPair(NULL, top_level_native_view), focus_changes[0]);
677
678   // Create a modal dialog.
679   // This instance will be destroyed when the dialog is destroyed.
680   ModalDialogDelegate* dialog_delegate =
681       new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
682
683   Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
684       dialog_delegate, NULL, top_level_widget.GetNativeView());
685   modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
686   modal_dialog_widget->Show();
687
688   gfx::NativeView modal_native_view = modal_dialog_widget->GetNativeView();
689   EXPECT_EQ(3u, focus_changes.size());
690   EXPECT_EQ(NativeViewPair(top_level_native_view, modal_native_view),
691             focus_changes[1]);
692   EXPECT_EQ(NativeViewPair(top_level_native_view, modal_native_view),
693             focus_changes[2]);
694
695   modal_dialog_widget->CloseNow();
696
697   EXPECT_EQ(5u, focus_changes.size());
698   EXPECT_EQ(NativeViewPair(modal_native_view, top_level_native_view),
699             focus_changes[3]);
700   EXPECT_EQ(NativeViewPair(modal_native_view, top_level_native_view),
701             focus_changes[4]);
702
703   top_level_widget.CloseNow();
704   WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
705 }
706
707 // Test that when opening a system-modal window, capture is released.
708 TEST_F(WidgetTestInteractive, SystemModalWindowReleasesCapture) {
709   TestWidgetFocusChangeListener focus_listener;
710   WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
711
712   // Create a top level widget.
713   Widget top_level_widget;
714   Widget::InitParams init_params =
715       CreateParams(Widget::InitParams::TYPE_WINDOW);
716   init_params.show_state = ui::SHOW_STATE_NORMAL;
717   gfx::Rect initial_bounds(0, 0, 500, 500);
718   init_params.bounds = initial_bounds;
719   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
720   init_params.native_widget =
721       new PlatformDesktopNativeWidget(&top_level_widget);
722   top_level_widget.Init(init_params);
723   top_level_widget.Show();
724
725   EXPECT_EQ(top_level_widget.GetNativeView(),
726             focus_listener.focus_changes().back().second);;
727
728   EXPECT_FALSE(top_level_widget.HasCapture());
729   top_level_widget.SetCapture(NULL);
730   EXPECT_TRUE(top_level_widget.HasCapture());
731
732   // Create a modal dialog.
733   ModalDialogDelegate* dialog_delegate =
734       new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
735
736   Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
737       dialog_delegate, NULL, top_level_widget.GetNativeView());
738   modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
739   modal_dialog_widget->Show();
740
741   EXPECT_FALSE(top_level_widget.HasCapture());
742
743   modal_dialog_widget->CloseNow();
744   top_level_widget.CloseNow();
745   WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
746 }
747
748 #endif  // !defined(OS_CHROMEOS)
749
750 TEST_F(WidgetTestInteractive, CanActivateFlagIsHonored) {
751   Widget widget;
752   Widget::InitParams init_params =
753       CreateParams(Widget::InitParams::TYPE_WINDOW);
754   init_params.bounds = gfx::Rect(0, 0, 200, 200);
755   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
756   init_params.activatable = Widget::InitParams::ACTIVATABLE_NO;
757 #if !defined(OS_CHROMEOS)
758   init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
759 #endif  // !defined(OS_CHROMEOS)
760   widget.Init(init_params);
761
762   widget.Show();
763   EXPECT_FALSE(widget.IsActive());
764 }
765
766 // Test that touch selection quick menu is not activated when opened.
767 TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) {
768   CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
769 #if defined(OS_WIN)
770   views_delegate().set_use_desktop_native_widgets(true);
771 #endif  // !defined(OS_WIN)
772
773   Widget widget;
774   Widget::InitParams init_params =
775       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
776   init_params.bounds = gfx::Rect(0, 0, 200, 200);
777   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
778   widget.Init(init_params);
779
780   Textfield* textfield = new Textfield;
781   textfield->SetBounds(0, 0, 200, 20);
782   textfield->SetText(base::ASCIIToUTF16("some text"));
783   widget.GetRootView()->AddChildView(textfield);
784
785   widget.Show();
786   textfield->RequestFocus();
787   textfield->SelectAll(true);
788   TextfieldTestApi textfield_test_api(textfield);
789
790   RunPendingMessages();
791
792   ui::test::EventGenerator generator(widget.GetNativeWindow());
793   generator.GestureTapAt(gfx::Point(10, 10));
794   ShowQuickMenuImmediately(static_cast<TouchSelectionControllerImpl*>(
795       textfield_test_api.touch_selection_controller()));
796
797   EXPECT_TRUE(textfield->HasFocus());
798   EXPECT_TRUE(widget.IsActive());
799   EXPECT_TRUE(IsQuickMenuVisible(static_cast<TouchSelectionControllerImpl*>(
800       textfield_test_api.touch_selection_controller())));
801 }
802
803 TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
804 #if defined(OS_WIN)
805   views_delegate().set_use_desktop_native_widgets(true);
806 #endif  // !defined(OS_WIN)
807
808   // Create first widget and view, activate the widget, and focus the view.
809   Widget widget1;
810   Widget::InitParams params1 = CreateParams(Widget::InitParams::TYPE_POPUP);
811   params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
812   params1.activatable = Widget::InitParams::ACTIVATABLE_YES;
813   widget1.Init(params1);
814
815   View* view1 = new View();
816   view1->SetFocusable(true);
817   widget1.GetRootView()->AddChildView(view1);
818
819   widget1.Activate();
820   EXPECT_TRUE(widget1.IsActive());
821
822   FocusManager* focus_manager1 = widget1.GetFocusManager();
823   ASSERT_TRUE(focus_manager1);
824   focus_manager1->SetFocusedView(view1);
825   EXPECT_EQ(view1, focus_manager1->GetFocusedView());
826
827   // Create second widget and view, activate the widget, and focus the view.
828   Widget widget2;
829   Widget::InitParams params2 = CreateParams(Widget::InitParams::TYPE_POPUP);
830   params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
831   params2.activatable = Widget::InitParams::ACTIVATABLE_YES;
832   widget2.Init(params2);
833
834   View* view2 = new View();
835   view2->SetFocusable(true);
836   widget2.GetRootView()->AddChildView(view2);
837
838   widget2.Activate();
839   EXPECT_TRUE(widget2.IsActive());
840   EXPECT_FALSE(widget1.IsActive());
841
842   FocusManager* focus_manager2 = widget2.GetFocusManager();
843   ASSERT_TRUE(focus_manager2);
844   focus_manager2->SetFocusedView(view2);
845   EXPECT_EQ(view2, focus_manager2->GetFocusedView());
846
847   // Disable the first view and make sure it loses focus, but its widget is not
848   // activated.
849   view1->SetEnabled(false);
850   EXPECT_NE(view1, focus_manager1->GetFocusedView());
851   EXPECT_FALSE(widget1.IsActive());
852   EXPECT_TRUE(widget2.IsActive());
853 }
854
855 namespace {
856
857 // Used to veirfy OnMouseCaptureLost() has been invoked.
858 class CaptureLostTrackingWidget : public Widget {
859  public:
860   CaptureLostTrackingWidget() : got_capture_lost_(false) {}
861   virtual ~CaptureLostTrackingWidget() {}
862
863   bool GetAndClearGotCaptureLost() {
864     bool value = got_capture_lost_;
865     got_capture_lost_ = false;
866     return value;
867   }
868
869   // Widget:
870   virtual void OnMouseCaptureLost() OVERRIDE {
871     got_capture_lost_ = true;
872     Widget::OnMouseCaptureLost();
873   }
874
875  private:
876   bool got_capture_lost_;
877
878   DISALLOW_COPY_AND_ASSIGN(CaptureLostTrackingWidget);
879 };
880
881 }  // namespace
882
883 class WidgetCaptureTest : public ViewsTestBase {
884  public:
885   WidgetCaptureTest() {
886   }
887
888   virtual ~WidgetCaptureTest() {
889   }
890
891   virtual void SetUp() OVERRIDE {
892     gfx::GLSurface::InitializeOneOffForTests();
893     ui::RegisterPathProvider();
894     base::FilePath ui_test_pak_path;
895     ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
896     ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
897     ViewsTestBase::SetUp();
898   }
899
900   // Verifies Widget::SetCapture() results in updating native capture along with
901   // invoking the right Widget function.
902   void TestCapture(bool use_desktop_native_widget) {
903     CaptureLostTrackingWidget widget1;
904     Widget::InitParams params1 =
905         CreateParams(views::Widget::InitParams::TYPE_WINDOW);
906     params1.native_widget = CreateNativeWidget(use_desktop_native_widget,
907                                                &widget1);
908     params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
909     widget1.Init(params1);
910     widget1.Show();
911
912     CaptureLostTrackingWidget widget2;
913     Widget::InitParams params2 =
914         CreateParams(views::Widget::InitParams::TYPE_WINDOW);
915     params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
916     params2.native_widget = CreateNativeWidget(use_desktop_native_widget,
917                                                &widget2);
918     widget2.Init(params2);
919     widget2.Show();
920
921     // Set capture to widget2 and verity it gets it.
922     widget2.SetCapture(widget2.GetRootView());
923     EXPECT_FALSE(widget1.HasCapture());
924     EXPECT_TRUE(widget2.HasCapture());
925     EXPECT_FALSE(widget1.GetAndClearGotCaptureLost());
926     EXPECT_FALSE(widget2.GetAndClearGotCaptureLost());
927
928     // Set capture to widget1 and verify it gets it.
929     widget1.SetCapture(widget1.GetRootView());
930     EXPECT_TRUE(widget1.HasCapture());
931     EXPECT_FALSE(widget2.HasCapture());
932     EXPECT_FALSE(widget1.GetAndClearGotCaptureLost());
933     EXPECT_TRUE(widget2.GetAndClearGotCaptureLost());
934
935     // Release and verify no one has it.
936     widget1.ReleaseCapture();
937     EXPECT_FALSE(widget1.HasCapture());
938     EXPECT_FALSE(widget2.HasCapture());
939     EXPECT_TRUE(widget1.GetAndClearGotCaptureLost());
940     EXPECT_FALSE(widget2.GetAndClearGotCaptureLost());
941   }
942
943   NativeWidget* CreateNativeWidget(bool create_desktop_native_widget,
944                                    Widget* widget) {
945 #if !defined(OS_CHROMEOS)
946     if (create_desktop_native_widget)
947       return new PlatformDesktopNativeWidget(widget);
948 #endif
949     return NULL;
950   }
951
952  private:
953   DISALLOW_COPY_AND_ASSIGN(WidgetCaptureTest);
954 };
955
956 // See description in TestCapture().
957 TEST_F(WidgetCaptureTest, Capture) {
958   TestCapture(false);
959 }
960
961 #if !defined(OS_CHROMEOS)
962 // See description in TestCapture(). Creates DesktopNativeWidget.
963 TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
964   TestCapture(true);
965 }
966 #endif
967
968 // Test that no state is set if capture fails.
969 TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
970   Widget widget;
971   Widget::InitParams params =
972       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
973   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
974   params.bounds = gfx::Rect(400, 400);
975   widget.Init(params);
976
977   MouseView* mouse_view1 = new MouseView;
978   MouseView* mouse_view2 = new MouseView;
979   View* contents_view = new View;
980   contents_view->AddChildView(mouse_view1);
981   contents_view->AddChildView(mouse_view2);
982   widget.SetContentsView(contents_view);
983
984   mouse_view1->SetBounds(0, 0, 200, 400);
985   mouse_view2->SetBounds(200, 0, 200, 400);
986
987   // Setting capture should fail because |widget| is not visible.
988   widget.SetCapture(mouse_view1);
989   EXPECT_FALSE(widget.HasCapture());
990
991   widget.Show();
992   ui::test::EventGenerator generator(GetContext(), widget.GetNativeWindow());
993   generator.set_current_location(gfx::Point(300, 10));
994   generator.PressLeftButton();
995
996   EXPECT_FALSE(mouse_view1->pressed());
997   EXPECT_TRUE(mouse_view2->pressed());
998 }
999
1000 #if !defined(OS_CHROMEOS) && !defined(OS_WIN)
1001 // Test that a synthetic mouse exit is sent to the widget which was handling
1002 // mouse events when a different widget grabs capture.
1003 // TODO(pkotwicz): Make test pass on CrOS and Windows.
1004 TEST_F(WidgetCaptureTest, MouseExitOnCaptureGrab) {
1005   Widget widget1;
1006   Widget::InitParams params1 =
1007       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1008   params1.native_widget = CreateNativeWidget(true, &widget1);
1009   params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1010   widget1.Init(params1);
1011   MouseView* mouse_view1 = new MouseView;
1012   widget1.SetContentsView(mouse_view1);
1013   widget1.Show();
1014   widget1.SetBounds(gfx::Rect(300, 300));
1015
1016   Widget widget2;
1017   Widget::InitParams params2 =
1018       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1019   params2.native_widget = CreateNativeWidget(true, &widget2);
1020   params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1021   widget2.Init(params2);
1022   widget2.Show();
1023   widget2.SetBounds(gfx::Rect(400, 0, 300, 300));
1024
1025   ui::test::EventGenerator generator(widget1.GetNativeWindow());
1026   generator.set_current_location(gfx::Point(100, 100));
1027   generator.MoveMouseBy(0, 0);
1028
1029   EXPECT_EQ(1, mouse_view1->EnteredCalls());
1030   EXPECT_EQ(0, mouse_view1->ExitedCalls());
1031
1032   widget2.SetCapture(NULL);
1033   EXPECT_EQ(0, mouse_view1->EnteredCalls());
1034   // Grabbing native capture on Windows generates a ui::ET_MOUSE_EXITED event
1035   // in addition to the one generated by Chrome.
1036   EXPECT_LT(0, mouse_view1->ExitedCalls());
1037 }
1038 #endif  // !defined(OS_CHROMEOS)
1039
1040 namespace {
1041
1042 // Widget observer which grabs capture when the widget is activated.
1043 class CaptureOnActivationObserver : public WidgetObserver {
1044  public:
1045   CaptureOnActivationObserver() {
1046   }
1047   virtual ~CaptureOnActivationObserver() {
1048   }
1049
1050   // WidgetObserver:
1051   virtual void OnWidgetActivationChanged(Widget* widget, bool active) OVERRIDE {
1052     if (active)
1053       widget->SetCapture(NULL);
1054   }
1055
1056  private:
1057   DISALLOW_COPY_AND_ASSIGN(CaptureOnActivationObserver);
1058 };
1059
1060 }  // namespace
1061
1062 // Test that setting capture on widget activation of a non-toplevel widget
1063 // (e.g. a bubble on Linux) succeeds.
1064 TEST_F(WidgetCaptureTest, SetCaptureToNonToplevel) {
1065   Widget toplevel;
1066   Widget::InitParams toplevel_params =
1067       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1068   toplevel_params.native_widget = CreateNativeWidget(true, &toplevel);
1069   toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1070   toplevel.Init(toplevel_params);
1071   toplevel.Show();
1072
1073   Widget* child = new Widget;
1074   Widget::InitParams child_params =
1075       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1076   child_params.parent = toplevel.GetNativeView();
1077   child_params.context = toplevel.GetNativeWindow();
1078   child->Init(child_params);
1079
1080   CaptureOnActivationObserver observer;
1081   child->AddObserver(&observer);
1082   child->Show();
1083
1084   EXPECT_TRUE(child->HasCapture());
1085 }
1086
1087
1088 #if defined(OS_WIN)
1089 namespace {
1090
1091 // Used to verify OnMouseEvent() has been invoked.
1092 class MouseEventTrackingWidget : public Widget {
1093  public:
1094   MouseEventTrackingWidget() : got_mouse_event_(false) {}
1095   virtual ~MouseEventTrackingWidget() {}
1096
1097   bool GetAndClearGotMouseEvent() {
1098     bool value = got_mouse_event_;
1099     got_mouse_event_ = false;
1100     return value;
1101   }
1102
1103   // Widget:
1104   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1105     got_mouse_event_ = true;
1106     Widget::OnMouseEvent(event);
1107   }
1108
1109  private:
1110   bool got_mouse_event_;
1111
1112   DISALLOW_COPY_AND_ASSIGN(MouseEventTrackingWidget);
1113 };
1114
1115 }  // namespace
1116
1117 // Verifies if a mouse event is received on a widget that doesn't have capture
1118 // on Windows that it is correctly processed by the widget that doesn't have
1119 // capture. This behavior is not desired on OSes other than Windows.
1120 TEST_F(WidgetCaptureTest, MouseEventDispatchedToRightWindow) {
1121   MouseEventTrackingWidget widget1;
1122   Widget::InitParams params1 =
1123       CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1124   params1.native_widget = new DesktopNativeWidgetAura(&widget1);
1125   params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1126   widget1.Init(params1);
1127   widget1.Show();
1128
1129   MouseEventTrackingWidget widget2;
1130   Widget::InitParams params2 =
1131       CreateParams(views::Widget::InitParams::TYPE_WINDOW);
1132   params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1133   params2.native_widget = new DesktopNativeWidgetAura(&widget2);
1134   widget2.Init(params2);
1135   widget2.Show();
1136
1137   // Set capture to widget2 and verity it gets it.
1138   widget2.SetCapture(widget2.GetRootView());
1139   EXPECT_FALSE(widget1.HasCapture());
1140   EXPECT_TRUE(widget2.HasCapture());
1141
1142   widget1.GetAndClearGotMouseEvent();
1143   widget2.GetAndClearGotMouseEvent();
1144   // Send a mouse event to the RootWindow associated with |widget1|. Even though
1145   // |widget2| has capture, |widget1| should still get the event.
1146   ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
1147                              ui::EF_NONE, ui::EF_NONE);
1148   ui::EventDispatchDetails details = widget1.GetNativeWindow()->
1149       GetHost()->event_processor()->OnEventFromSource(&mouse_event);
1150   ASSERT_FALSE(details.dispatcher_destroyed);
1151   EXPECT_TRUE(widget1.GetAndClearGotMouseEvent());
1152   EXPECT_FALSE(widget2.GetAndClearGotMouseEvent());
1153 }
1154 #endif  // defined(OS_WIN)
1155
1156 }  // namespace test
1157 }  // namespace views