- add sources.
[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/run_loop.h"
8 #include "ui/gfx/native_widget_types.h"
9 #include "ui/views/test/widget_test.h"
10 #include "ui/views/widget/widget.h"
11 #include "ui/views/window/dialog_delegate.h"
12
13 #if defined(USE_AURA)
14 #include "ui/aura/client/activation_client.h"
15 #include "ui/aura/client/focus_client.h"
16 #include "ui/aura/env.h"
17 #include "ui/aura/root_window.h"
18 #endif
19
20 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
21 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
22 #endif
23
24 #if defined(OS_WIN)
25 #include "ui/views/win/hwnd_util.h"
26 #endif
27
28 namespace views {
29 namespace test {
30
31 namespace {
32
33 // A View that closes the Widget and exits the current message-loop when it
34 // receives a mouse-release event.
35 class ExitLoopOnRelease : public View {
36  public:
37   ExitLoopOnRelease() {}
38   virtual ~ExitLoopOnRelease() {}
39
40  private:
41   // Overridden from View:
42   virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
43     GetWidget()->Close();
44     base::MessageLoop::current()->QuitNow();
45   }
46
47   DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease);
48 };
49
50 // A view that does a capture on gesture-begin events.
51 class GestureCaptureView : public View {
52  public:
53   GestureCaptureView() {}
54   virtual ~GestureCaptureView() {}
55
56  private:
57   // Overridden from View:
58   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
59     if (event->type() == ui::ET_GESTURE_BEGIN) {
60       GetWidget()->SetCapture(this);
61       event->StopPropagation();
62     }
63   }
64
65   DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
66 };
67
68 // A view that always processes all mouse events.
69 class MouseView : public View {
70  public:
71   MouseView()
72       : View(),
73         entered_(0),
74         exited_(0),
75         pressed_(0) {
76   }
77   virtual ~MouseView() {}
78
79   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
80     pressed_++;
81     return true;
82   }
83
84   virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
85     entered_++;
86   }
87
88   virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
89     exited_++;
90   }
91
92   // Return the number of OnMouseEntered calls and reset the counter.
93   int EnteredCalls() {
94     int i = entered_;
95     entered_ = 0;
96     return i;
97   }
98
99   // Return the number of OnMouseExited calls and reset the counter.
100   int ExitedCalls() {
101     int i = exited_;
102     exited_ = 0;
103     return i;
104   }
105
106   int pressed() const { return pressed_; }
107
108  private:
109   int entered_;
110   int exited_;
111
112   int pressed_;
113
114   DISALLOW_COPY_AND_ASSIGN(MouseView);
115 };
116
117 // A View that shows a different widget, sets capture on that widget, and
118 // initiates a nested message-loop when it receives a mouse-press event.
119 class NestedLoopCaptureView : public View {
120  public:
121   explicit NestedLoopCaptureView(Widget* widget) : widget_(widget) {}
122   virtual ~NestedLoopCaptureView() {}
123
124  private:
125   // Overridden from View:
126   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
127     // Start a nested loop.
128     widget_->Show();
129     widget_->SetCapture(widget_->GetContentsView());
130     EXPECT_TRUE(widget_->HasCapture());
131
132     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
133     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
134
135     base::RunLoop run_loop;
136 #if defined(USE_AURA)
137     run_loop.set_dispatcher(aura::Env::GetInstance()->GetDispatcher());
138 #endif
139     run_loop.Run();
140     return true;
141   }
142
143   Widget* widget_;
144
145   DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView);
146 };
147
148 }  // namespace
149
150 #if defined(OS_WIN) && defined(USE_AURA)
151 // Tests whether activation and focus change works correctly in Windows AURA.
152 // We test the following:-
153 // 1. If the active aura window is correctly set when a top level widget is
154 //    created.
155 // 2. If the active aura window in widget 1 created above, is set to NULL when
156 //    another top level widget is created and focused.
157 // 3. On focusing the native platform window for widget 1, the active aura
158 //    window for widget 1 should be set and that for widget 2 should reset.
159 // TODO(ananta)
160 // Discuss with erg on how to write this test for linux x11 aura.
161 TEST_F(WidgetTest, DesktopNativeWidgetAuraActivationAndFocusTest) {
162   // Create widget 1 and expect the active window to be its window.
163   View* contents_view1 = new View;
164   contents_view1->set_focusable(true);
165   Widget widget1;
166   Widget::InitParams init_params =
167       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
168   init_params.bounds = gfx::Rect(0, 0, 200, 200);
169   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
170   init_params.native_widget = new DesktopNativeWidgetAura(&widget1);
171   widget1.Init(init_params);
172   widget1.SetContentsView(contents_view1);
173   widget1.Show();
174   aura::Window* root_window1= widget1.GetNativeView()->GetRootWindow();
175   contents_view1->RequestFocus();
176
177   EXPECT_TRUE(root_window1 != NULL);
178   aura::client::ActivationClient* activation_client1 =
179       aura::client::GetActivationClient(root_window1);
180   EXPECT_TRUE(activation_client1 != NULL);
181   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
182
183   // Create widget 2 and expect the active window to be its window.
184   View* contents_view2 = new View;
185   Widget widget2;
186   Widget::InitParams init_params2 =
187       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
188   init_params2.bounds = gfx::Rect(0, 0, 200, 200);
189   init_params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
190   init_params2.native_widget = new DesktopNativeWidgetAura(&widget2);
191   widget2.Init(init_params2);
192   widget2.SetContentsView(contents_view2);
193   widget2.Show();
194   aura::Window* root_window2 = widget2.GetNativeView()->GetRootWindow();
195   contents_view2->RequestFocus();
196   ::SetActiveWindow(root_window2->GetDispatcher()->GetAcceleratedWidget());
197
198   aura::client::ActivationClient* activation_client2 =
199       aura::client::GetActivationClient(root_window2);
200   EXPECT_TRUE(activation_client2 != NULL);
201   EXPECT_EQ(activation_client2->GetActiveWindow(), widget2.GetNativeView());
202   EXPECT_EQ(activation_client1->GetActiveWindow(),
203             reinterpret_cast<aura::Window*>(NULL));
204
205   // Now set focus back to widget 1 and expect the active window to be its
206   // window.
207   contents_view1->RequestFocus();
208   ::SetActiveWindow(root_window1->GetDispatcher()->GetAcceleratedWidget());
209   EXPECT_EQ(activation_client2->GetActiveWindow(),
210             reinterpret_cast<aura::Window*>(NULL));
211   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
212 }
213 #endif
214
215 TEST_F(WidgetTest, CaptureAutoReset) {
216   Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
217   View* container = new View;
218   toplevel->SetContentsView(container);
219
220   EXPECT_FALSE(toplevel->HasCapture());
221   toplevel->SetCapture(NULL);
222   EXPECT_TRUE(toplevel->HasCapture());
223
224   // By default, mouse release removes capture.
225   gfx::Point click_location(45, 15);
226   ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
227       ui::EF_LEFT_MOUSE_BUTTON);
228   toplevel->OnMouseEvent(&release);
229   EXPECT_FALSE(toplevel->HasCapture());
230
231   // Now a mouse release shouldn't remove capture.
232   toplevel->set_auto_release_capture(false);
233   toplevel->SetCapture(NULL);
234   EXPECT_TRUE(toplevel->HasCapture());
235   toplevel->OnMouseEvent(&release);
236   EXPECT_TRUE(toplevel->HasCapture());
237   toplevel->ReleaseCapture();
238   EXPECT_FALSE(toplevel->HasCapture());
239
240   toplevel->Close();
241   RunPendingMessages();
242 }
243
244 TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
245   Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
246   View* container = new View;
247   toplevel->SetContentsView(container);
248
249   View* gesture = new GestureCaptureView;
250   gesture->SetBounds(0, 0, 30, 30);
251   container->AddChildView(gesture);
252
253   MouseView* mouse = new MouseView;
254   mouse->SetBounds(30, 0, 30, 30);
255   container->AddChildView(mouse);
256
257   toplevel->SetSize(gfx::Size(100, 100));
258   toplevel->Show();
259
260   // Start a gesture on |gesture|.
261   ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
262       15, 15, 0, base::TimeDelta(),
263       ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
264   ui::GestureEvent end(ui::ET_GESTURE_END,
265       15, 15, 0, base::TimeDelta(),
266       ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
267   toplevel->OnGestureEvent(&begin);
268
269   // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
270   // will not receive the event.
271   gfx::Point click_location(45, 15);
272
273   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
274       ui::EF_LEFT_MOUSE_BUTTON);
275   ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
276       ui::EF_LEFT_MOUSE_BUTTON);
277
278   EXPECT_TRUE(toplevel->HasCapture());
279
280   toplevel->OnMouseEvent(&press);
281   toplevel->OnMouseEvent(&release);
282   EXPECT_EQ(0, mouse->pressed());
283
284   EXPECT_FALSE(toplevel->HasCapture());
285
286   // The end of the gesture should release the capture, and pressing on |mouse|
287   // should now reach |mouse|.
288   toplevel->OnGestureEvent(&end);
289   toplevel->OnMouseEvent(&press);
290   toplevel->OnMouseEvent(&release);
291   EXPECT_EQ(1, mouse->pressed());
292
293   toplevel->Close();
294   RunPendingMessages();
295 }
296
297 // Checks that if a mouse-press triggers a capture on a different widget (which
298 // consumes the mouse-release event), then the target of the press does not have
299 // capture.
300 TEST_F(WidgetTest, DisableCaptureWidgetFromMousePress) {
301   // The test creates two widgets: |first| and |second|.
302   // The View in |first| makes |second| visible, sets capture on it, and starts
303   // a nested loop (like a menu does). The View in |second| terminates the
304   // nested loop and closes the widget.
305   // The test sends a mouse-press event to |first|, and posts a task to send a
306   // release event to |second|, to make sure that the release event is
307   // dispatched after the nested loop starts.
308
309   Widget* first = CreateTopLevelFramelessPlatformWidget();
310   Widget* second = CreateTopLevelFramelessPlatformWidget();
311
312   View* container = new NestedLoopCaptureView(second);
313   first->SetContentsView(container);
314
315   second->SetContentsView(new ExitLoopOnRelease());
316
317   first->SetSize(gfx::Size(100, 100));
318   first->Show();
319
320   gfx::Point location(20, 20);
321   base::MessageLoop::current()->PostTask(FROM_HERE,
322       base::Bind(&Widget::OnMouseEvent,
323                  base::Unretained(second),
324                  base::Owned(new ui::MouseEvent(ui::ET_MOUSE_RELEASED,
325                                                 location,
326                                                 location,
327                                                 ui::EF_LEFT_MOUSE_BUTTON))));
328   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
329                        ui::EF_LEFT_MOUSE_BUTTON);
330   first->OnMouseEvent(&press);
331   EXPECT_FALSE(first->HasCapture());
332   first->Close();
333   RunPendingMessages();
334 }
335
336 // Tests some grab/ungrab events.
337 // TODO(estade): can this be enabled now that this is an interactive ui test?
338 TEST_F(WidgetTest, DISABLED_GrabUngrab) {
339   Widget* toplevel = CreateTopLevelPlatformWidget();
340   Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
341   Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
342
343   toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
344
345   child1->SetBounds(gfx::Rect(10, 10, 300, 300));
346   View* view = new MouseView();
347   view->SetBounds(0, 0, 300, 300);
348   child1->GetRootView()->AddChildView(view);
349
350   child2->SetBounds(gfx::Rect(200, 10, 200, 200));
351   view = new MouseView();
352   view->SetBounds(0, 0, 200, 200);
353   child2->GetRootView()->AddChildView(view);
354
355   toplevel->Show();
356   RunPendingMessages();
357
358   // Click on child1
359   gfx::Point p1(45, 45);
360   ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
361                          ui::EF_LEFT_MOUSE_BUTTON);
362   toplevel->OnMouseEvent(&pressed);
363
364   EXPECT_TRUE(toplevel->HasCapture());
365   EXPECT_TRUE(child1->HasCapture());
366   EXPECT_FALSE(child2->HasCapture());
367
368   ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
369                           ui::EF_LEFT_MOUSE_BUTTON);
370   toplevel->OnMouseEvent(&released);
371
372   EXPECT_FALSE(toplevel->HasCapture());
373   EXPECT_FALSE(child1->HasCapture());
374   EXPECT_FALSE(child2->HasCapture());
375
376   RunPendingMessages();
377
378   // Click on child2
379   gfx::Point p2(315, 45);
380   ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
381                           ui::EF_LEFT_MOUSE_BUTTON);
382   toplevel->OnMouseEvent(&pressed2);
383   EXPECT_TRUE(pressed2.handled());
384   EXPECT_TRUE(toplevel->HasCapture());
385   EXPECT_TRUE(child2->HasCapture());
386   EXPECT_FALSE(child1->HasCapture());
387
388   ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
389                            ui::EF_LEFT_MOUSE_BUTTON);
390   toplevel->OnMouseEvent(&released2);
391   EXPECT_FALSE(toplevel->HasCapture());
392   EXPECT_FALSE(child1->HasCapture());
393   EXPECT_FALSE(child2->HasCapture());
394
395   toplevel->CloseNow();
396 }
397
398 // Tests mouse move outside of the window into the "resize controller" and back
399 // will still generate an OnMouseEntered and OnMouseExited event..
400 TEST_F(WidgetTest, CheckResizeControllerEvents) {
401   Widget* toplevel = CreateTopLevelPlatformWidget();
402
403   toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
404
405   MouseView* view = new MouseView();
406   view->SetBounds(90, 90, 10, 10);
407   toplevel->GetRootView()->AddChildView(view);
408
409   toplevel->Show();
410   RunPendingMessages();
411
412   // Move to an outside position.
413   gfx::Point p1(200, 200);
414   ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE);
415   toplevel->OnMouseEvent(&moved_out);
416   EXPECT_EQ(0, view->EnteredCalls());
417   EXPECT_EQ(0, view->ExitedCalls());
418
419   // Move onto the active view.
420   gfx::Point p2(95, 95);
421   ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE);
422   toplevel->OnMouseEvent(&moved_over);
423   EXPECT_EQ(1, view->EnteredCalls());
424   EXPECT_EQ(0, view->ExitedCalls());
425
426   // Move onto the outer resizing border.
427   gfx::Point p3(102, 95);
428   ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE);
429   toplevel->OnMouseEvent(&moved_resizer);
430   EXPECT_EQ(0, view->EnteredCalls());
431   EXPECT_EQ(1, view->ExitedCalls());
432
433   // Move onto the view again.
434   toplevel->OnMouseEvent(&moved_over);
435   EXPECT_EQ(1, view->EnteredCalls());
436   EXPECT_EQ(0, view->ExitedCalls());
437
438   RunPendingMessages();
439
440   toplevel->CloseNow();
441 }
442
443 #if defined(OS_WIN)
444
445 // This class subclasses the Widget class to listen for activation change
446 // notifications and provides accessors to return information as to whether
447 // the widget is active. We need this to ensure that users of the widget
448 // class activate the widget only when the underlying window becomes really
449 // active. Previously we would activate the widget in the WM_NCACTIVATE
450 // message which is incorrect because APIs like FlashWindowEx flash the
451 // window caption by sending fake WM_NCACTIVATE messages.
452 class WidgetActivationTest : public Widget {
453  public:
454   WidgetActivationTest()
455       : active_(false) {}
456
457   virtual ~WidgetActivationTest() {}
458
459   virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE {
460     active_ = active;
461   }
462
463   bool active() const { return active_; }
464
465  private:
466   bool active_;
467
468   DISALLOW_COPY_AND_ASSIGN(WidgetActivationTest);
469 };
470
471 // Tests whether the widget only becomes active when the underlying window
472 // is really active.
473 TEST_F(WidgetTest, WidgetNotActivatedOnFakeActivationMessages) {
474   WidgetActivationTest widget1;
475   Widget::InitParams init_params =
476       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
477   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
478 #if defined(USE_AURA)
479   init_params.native_widget = new DesktopNativeWidgetAura(&widget1);
480 #endif
481   init_params.bounds = gfx::Rect(0, 0, 200, 200);
482   widget1.Init(init_params);
483   widget1.Show();
484   EXPECT_EQ(true, widget1.active());
485
486   WidgetActivationTest widget2;
487 #if defined(USE_AURA)
488   init_params.native_widget = new DesktopNativeWidgetAura(&widget2);
489 #endif
490   widget2.Init(init_params);
491   widget2.Show();
492   EXPECT_EQ(true, widget2.active());
493   EXPECT_EQ(false, widget1.active());
494
495   HWND win32_native_window1 = HWNDForWidget(&widget1);
496   EXPECT_TRUE(::IsWindow(win32_native_window1));
497
498   ::SendMessage(win32_native_window1, WM_NCACTIVATE, 1, 0);
499   EXPECT_EQ(false, widget1.active());
500   EXPECT_EQ(true, widget2.active());
501
502   ::SetActiveWindow(win32_native_window1);
503   EXPECT_EQ(true, widget1.active());
504   EXPECT_EQ(false, widget2.active());
505 }
506 #endif
507
508 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
509 // Provides functionality to create a window modal dialog.
510 class ModalDialogDelegate : public DialogDelegateView {
511  public:
512   ModalDialogDelegate() {}
513   virtual ~ModalDialogDelegate() {}
514
515   // WidgetDelegate overrides.
516   virtual ui::ModalType GetModalType() const OVERRIDE {
517     return ui::MODAL_TYPE_WINDOW;
518   }
519
520  private:
521   DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
522 };
523
524 // Tests whether the focused window is set correctly when a modal window is
525 // created and destroyed. When it is destroyed it should focus the owner
526 // window.
527 TEST_F(WidgetTest, WindowModalWindowDestroyedActivationTest) {
528   // Create a top level widget.
529   Widget top_level_widget;
530   Widget::InitParams init_params =
531       CreateParams(Widget::InitParams::TYPE_WINDOW);
532   init_params.show_state = ui::SHOW_STATE_NORMAL;
533   gfx::Rect initial_bounds(0, 0, 500, 500);
534   init_params.bounds = initial_bounds;
535   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
536   init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
537   top_level_widget.Init(init_params);
538   top_level_widget.Show();
539
540   aura::Window* top_level_window = top_level_widget.GetNativeWindow();
541   EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
542                 top_level_window)->GetFocusedWindow());
543
544   // Create a modal dialog.
545   // This instance will be destroyed when the dialog is destroyed.
546   ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
547
548   Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
549       dialog_delegate, NULL, top_level_widget.GetNativeWindow());
550   modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
551   modal_dialog_widget->Show();
552   aura::Window* dialog_window = modal_dialog_widget->GetNativeWindow();
553   EXPECT_EQ(dialog_window, aura::client::GetFocusClient(
554                 top_level_window)->GetFocusedWindow());
555
556   modal_dialog_widget->CloseNow();
557   EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
558                 top_level_window)->GetFocusedWindow());
559   top_level_widget.CloseNow();
560 }
561 #endif
562
563 namespace {
564
565 // Used to veirfy OnMouseCaptureLost() has been invoked.
566 class CaptureLostTrackingWidget : public Widget {
567  public:
568   CaptureLostTrackingWidget() : got_capture_lost_(false) {}
569   virtual ~CaptureLostTrackingWidget() {}
570
571   bool GetAndClearGotCaptureLost() {
572     bool value = got_capture_lost_;
573     got_capture_lost_ = false;
574     return value;
575   }
576
577   // Widget:
578   virtual void OnMouseCaptureLost() OVERRIDE {
579     got_capture_lost_ = true;
580     Widget::OnMouseCaptureLost();
581   }
582
583  private:
584   bool got_capture_lost_;
585
586   DISALLOW_COPY_AND_ASSIGN(CaptureLostTrackingWidget);
587 };
588
589 }  // namespace
590
591 class WidgetCaptureTest : public ViewsTestBase {
592  public:
593   WidgetCaptureTest() {
594   }
595
596   virtual ~WidgetCaptureTest() {
597   }
598
599   // Verifies Widget::SetCapture() results in updating native capture along with
600   // invoking the right Widget function.
601   void TestCapture(bool use_desktop_native_widget) {
602     CaptureLostTrackingWidget widget1;
603     Widget::InitParams params1 =
604         CreateParams(views::Widget::InitParams::TYPE_WINDOW);
605     params1.native_widget = CreateNativeWidget(use_desktop_native_widget,
606                                                &widget1);
607     params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
608     widget1.Init(params1);
609     widget1.Show();
610
611     CaptureLostTrackingWidget widget2;
612     Widget::InitParams params2 =
613         CreateParams(views::Widget::InitParams::TYPE_WINDOW);
614     params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
615     params2.native_widget = CreateNativeWidget(use_desktop_native_widget,
616                                                &widget2);
617     widget2.Init(params2);
618     widget2.Show();
619
620     // Set capture to widget2 and verity it gets it.
621     widget2.SetCapture(widget2.GetRootView());
622     EXPECT_FALSE(widget1.HasCapture());
623     EXPECT_TRUE(widget2.HasCapture());
624     EXPECT_FALSE(widget1.GetAndClearGotCaptureLost());
625     EXPECT_FALSE(widget2.GetAndClearGotCaptureLost());
626
627     // Set capture to widget1 and verify it gets it.
628     widget1.SetCapture(widget1.GetRootView());
629     EXPECT_TRUE(widget1.HasCapture());
630     EXPECT_FALSE(widget2.HasCapture());
631     EXPECT_FALSE(widget1.GetAndClearGotCaptureLost());
632     EXPECT_TRUE(widget2.GetAndClearGotCaptureLost());
633
634     // Release and verify no one has it.
635     widget1.ReleaseCapture();
636     EXPECT_FALSE(widget1.HasCapture());
637     EXPECT_FALSE(widget2.HasCapture());
638     EXPECT_TRUE(widget1.GetAndClearGotCaptureLost());
639     EXPECT_FALSE(widget2.GetAndClearGotCaptureLost());
640   }
641
642  private:
643   NativeWidget* CreateNativeWidget(bool create_desktop_native_widget,
644                                    Widget* widget) {
645 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
646     if (create_desktop_native_widget)
647       return new DesktopNativeWidgetAura(widget);
648 #endif
649     return NULL;
650   }
651
652   DISALLOW_COPY_AND_ASSIGN(WidgetCaptureTest);
653 };
654
655 // See description in TestCapture().
656 TEST_F(WidgetCaptureTest, Capture) {
657   TestCapture(false);
658 }
659
660 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
661 // See description in TestCapture(). Creates DesktopNativeWidget.
662 TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
663   TestCapture(true);
664 }
665 #endif
666
667 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
668 namespace {
669
670 // Used to veirfy OnMouseEvent() has been invoked.
671 class MouseEventTrackingWidget : public Widget {
672  public:
673   MouseEventTrackingWidget() : got_mouse_event_(false) {}
674   virtual ~MouseEventTrackingWidget() {}
675
676   bool GetAndClearGotMouseEvent() {
677     bool value = got_mouse_event_;
678     got_mouse_event_ = false;
679     return value;
680   }
681
682   // Widget:
683   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
684     got_mouse_event_ = true;
685     Widget::OnMouseEvent(event);
686   }
687
688  private:
689   bool got_mouse_event_;
690
691   DISALLOW_COPY_AND_ASSIGN(MouseEventTrackingWidget);
692 };
693
694 }  // namespace
695
696 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
697 // TODO(erg): linux_aura bringup: http://crbug.com/163931
698 #define MAYBE_MouseEventDispatchedToRightWindow \
699   DISABLED_MouseEventDispatchedToRightWindow
700 #else
701 #define MAYBE_MouseEventDispatchedToRightWindow \
702   MouseEventDispatchedToRightWindow
703 #endif
704
705 // Verifies if a mouse event is received on a widget that doesn't have capture
706 // it is correctly processed by the widget that doesn't have capture.
707 TEST_F(WidgetCaptureTest, MAYBE_MouseEventDispatchedToRightWindow) {
708   MouseEventTrackingWidget widget1;
709   Widget::InitParams params1 =
710       CreateParams(views::Widget::InitParams::TYPE_WINDOW);
711   params1.native_widget = new DesktopNativeWidgetAura(&widget1);
712   params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
713   widget1.Init(params1);
714   widget1.Show();
715
716   MouseEventTrackingWidget widget2;
717   Widget::InitParams params2 =
718       CreateParams(views::Widget::InitParams::TYPE_WINDOW);
719   params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
720   params2.native_widget = new DesktopNativeWidgetAura(&widget2);
721   widget2.Init(params2);
722   widget2.Show();
723
724   // Set capture to widget2 and verity it gets it.
725   widget2.SetCapture(widget2.GetRootView());
726   EXPECT_FALSE(widget1.HasCapture());
727   EXPECT_TRUE(widget2.HasCapture());
728
729   widget1.GetAndClearGotMouseEvent();
730   widget2.GetAndClearGotMouseEvent();
731   // Send a mouse event to the RootWindow associated with |widget1|. Even though
732   // |widget2| has capture, |widget1| should still get the event.
733   ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
734                              ui::EF_NONE);
735   widget1.GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate()->
736       OnHostMouseEvent(&mouse_event);
737   EXPECT_TRUE(widget1.GetAndClearGotMouseEvent());
738   EXPECT_FALSE(widget2.GetAndClearGotMouseEvent());
739 }
740 #endif
741
742 }  // namespace test
743 }  // namespace views