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