Correct blacklist entry message
[chromium-blink-merge.git] / ui / views / widget / widget_interactive_uitest.cc
blobf08fe8b72b93aa2556fe87b721bc8d143897348b
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.
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"
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
20 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
21 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
22 #endif
24 #if defined(OS_WIN)
25 #include "ui/views/win/hwnd_util.h"
26 #endif
28 namespace views {
29 namespace test {
31 namespace {
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() {}
40 private:
41 // Overridden from View:
42 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
43 GetWidget()->Close();
44 base::MessageLoop::current()->QuitNow();
47 DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease);
50 // A view that does a capture on gesture-begin events.
51 class GestureCaptureView : public View {
52 public:
53 GestureCaptureView() {}
54 virtual ~GestureCaptureView() {}
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();
65 DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
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) {
77 virtual ~MouseView() {}
79 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
80 pressed_++;
81 return true;
84 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
85 entered_++;
88 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
89 exited_++;
92 // Return the number of OnMouseEntered calls and reset the counter.
93 int EnteredCalls() {
94 int i = entered_;
95 entered_ = 0;
96 return i;
99 // Return the number of OnMouseExited calls and reset the counter.
100 int ExitedCalls() {
101 int i = exited_;
102 exited_ = 0;
103 return i;
106 int pressed() const { return pressed_; }
108 private:
109 int entered_;
110 int exited_;
112 int pressed_;
114 DISALLOW_COPY_AND_ASSIGN(MouseView);
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() {}
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());
132 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
133 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
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;
143 Widget* widget_;
145 DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView);
148 } // namespace
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();
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());
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());
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));
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());
213 #endif
215 TEST_F(WidgetTest, CaptureAutoReset) {
216 Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
217 View* container = new View;
218 toplevel->SetContentsView(container);
220 EXPECT_FALSE(toplevel->HasCapture());
221 toplevel->SetCapture(NULL);
222 EXPECT_TRUE(toplevel->HasCapture());
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());
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());
240 toplevel->Close();
241 RunPendingMessages();
244 TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
245 Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
246 View* container = new View;
247 toplevel->SetContentsView(container);
249 View* gesture = new GestureCaptureView;
250 gesture->SetBounds(0, 0, 30, 30);
251 container->AddChildView(gesture);
253 MouseView* mouse = new MouseView;
254 mouse->SetBounds(30, 0, 30, 30);
255 container->AddChildView(mouse);
257 toplevel->SetSize(gfx::Size(100, 100));
258 toplevel->Show();
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);
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);
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);
278 EXPECT_TRUE(toplevel->HasCapture());
280 toplevel->OnMouseEvent(&press);
281 toplevel->OnMouseEvent(&release);
282 EXPECT_EQ(0, mouse->pressed());
284 EXPECT_FALSE(toplevel->HasCapture());
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());
293 toplevel->Close();
294 RunPendingMessages();
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.
309 Widget* first = CreateTopLevelFramelessPlatformWidget();
310 Widget* second = CreateTopLevelFramelessPlatformWidget();
312 View* container = new NestedLoopCaptureView(second);
313 first->SetContentsView(container);
315 second->SetContentsView(new ExitLoopOnRelease());
317 first->SetSize(gfx::Size(100, 100));
318 first->Show();
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();
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);
343 toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
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);
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);
355 toplevel->Show();
356 RunPendingMessages();
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);
364 EXPECT_TRUE(toplevel->HasCapture());
365 EXPECT_TRUE(child1->HasCapture());
366 EXPECT_FALSE(child2->HasCapture());
368 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
369 ui::EF_LEFT_MOUSE_BUTTON);
370 toplevel->OnMouseEvent(&released);
372 EXPECT_FALSE(toplevel->HasCapture());
373 EXPECT_FALSE(child1->HasCapture());
374 EXPECT_FALSE(child2->HasCapture());
376 RunPendingMessages();
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());
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());
395 toplevel->CloseNow();
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();
403 toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
405 MouseView* view = new MouseView();
406 view->SetBounds(90, 90, 10, 10);
407 toplevel->GetRootView()->AddChildView(view);
409 toplevel->Show();
410 RunPendingMessages();
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());
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());
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());
433 // Move onto the view again.
434 toplevel->OnMouseEvent(&moved_over);
435 EXPECT_EQ(1, view->EnteredCalls());
436 EXPECT_EQ(0, view->ExitedCalls());
438 RunPendingMessages();
440 toplevel->CloseNow();
443 #if defined(OS_WIN)
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) {}
457 virtual ~WidgetActivationTest() {}
459 virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE {
460 active_ = active;
463 bool active() const { return active_; }
465 private:
466 bool active_;
468 DISALLOW_COPY_AND_ASSIGN(WidgetActivationTest);
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());
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());
495 HWND win32_native_window1 = HWNDForWidget(&widget1);
496 EXPECT_TRUE(::IsWindow(win32_native_window1));
498 ::SendMessage(win32_native_window1, WM_NCACTIVATE, 1, 0);
499 EXPECT_EQ(false, widget1.active());
500 EXPECT_EQ(true, widget2.active());
502 ::SetActiveWindow(win32_native_window1);
503 EXPECT_EQ(true, widget1.active());
504 EXPECT_EQ(false, widget2.active());
506 #endif
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() {}
515 // WidgetDelegate overrides.
516 virtual ui::ModalType GetModalType() const OVERRIDE {
517 return ui::MODAL_TYPE_WINDOW;
520 private:
521 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
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();
540 aura::Window* top_level_window = top_level_widget.GetNativeWindow();
541 EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
542 top_level_window)->GetFocusedWindow());
544 // Create a modal dialog.
545 // This instance will be destroyed when the dialog is destroyed.
546 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
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());
556 modal_dialog_widget->CloseNow();
557 EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
558 top_level_window)->GetFocusedWindow());
559 top_level_widget.CloseNow();
561 #endif
563 namespace {
565 // Used to veirfy OnMouseCaptureLost() has been invoked.
566 class CaptureLostTrackingWidget : public Widget {
567 public:
568 CaptureLostTrackingWidget() : got_capture_lost_(false) {}
569 virtual ~CaptureLostTrackingWidget() {}
571 bool GetAndClearGotCaptureLost() {
572 bool value = got_capture_lost_;
573 got_capture_lost_ = false;
574 return value;
577 // Widget:
578 virtual void OnMouseCaptureLost() OVERRIDE {
579 got_capture_lost_ = true;
580 Widget::OnMouseCaptureLost();
583 private:
584 bool got_capture_lost_;
586 DISALLOW_COPY_AND_ASSIGN(CaptureLostTrackingWidget);
589 } // namespace
591 class WidgetCaptureTest : public ViewsTestBase {
592 public:
593 WidgetCaptureTest() {
596 virtual ~WidgetCaptureTest() {
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();
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();
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());
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());
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());
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;
652 DISALLOW_COPY_AND_ASSIGN(WidgetCaptureTest);
655 // See description in TestCapture().
656 TEST_F(WidgetCaptureTest, Capture) {
657 TestCapture(false);
660 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
661 // See description in TestCapture(). Creates DesktopNativeWidget.
662 TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
663 TestCapture(true);
665 #endif
667 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
668 namespace {
670 // Used to veirfy OnMouseEvent() has been invoked.
671 class MouseEventTrackingWidget : public Widget {
672 public:
673 MouseEventTrackingWidget() : got_mouse_event_(false) {}
674 virtual ~MouseEventTrackingWidget() {}
676 bool GetAndClearGotMouseEvent() {
677 bool value = got_mouse_event_;
678 got_mouse_event_ = false;
679 return value;
682 // Widget:
683 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
684 got_mouse_event_ = true;
685 Widget::OnMouseEvent(event);
688 private:
689 bool got_mouse_event_;
691 DISALLOW_COPY_AND_ASSIGN(MouseEventTrackingWidget);
694 } // namespace
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
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();
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();
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());
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());
740 #endif
742 } // namespace test
743 } // namespace views