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"
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"
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"
21 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
22 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
26 #include "ui/views/win/hwnd_util.h"
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 {
38 ExitLoopOnRelease() {}
39 virtual ~ExitLoopOnRelease() {}
42 // Overridden from View:
43 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
45 base::MessageLoop::current()->QuitNow();
48 DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease);
51 // A view that does a capture on gesture-begin events.
52 class GestureCaptureView : public View {
54 GestureCaptureView() {}
55 virtual ~GestureCaptureView() {}
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();
66 DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
69 // A view that always processes all mouse events.
70 class MouseView : public View {
78 virtual ~MouseView() {}
80 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
85 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
89 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
93 // Return the number of OnMouseEntered calls and reset the counter.
100 // Return the number of OnMouseExited calls and reset the counter.
107 int pressed() const { return pressed_; }
115 DISALLOW_COPY_AND_ASSIGN(MouseView);
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 {
122 explicit NestedLoopCaptureView(Widget* widget) : widget_(widget) {}
123 virtual ~NestedLoopCaptureView() {}
126 // Overridden from View:
127 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
128 // Start a nested loop.
130 widget_->SetCapture(widget_->GetContentsView());
131 EXPECT_TRUE(widget_->HasCapture());
133 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
134 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
136 base::RunLoop run_loop;
143 DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView);
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
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.
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);
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);
172 aura::Window* root_window1= widget1.GetNativeView()->GetRootWindow();
173 contents_view1->RequestFocus();
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());
181 // Create widget 2 and expect the active window to be its window.
182 View* contents_view2 = new View;
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);
192 aura::Window* root_window2 = widget2.GetNativeView()->GetRootWindow();
193 contents_view2->RequestFocus();
195 root_window2->GetDispatcher()->host()->GetAcceleratedWidget());
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));
204 // Now set focus back to widget 1 and expect the active window to be its
206 contents_view1->RequestFocus();
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());
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, 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());
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));
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, 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);
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());
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
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));
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,
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());
334 RunPendingMessages();
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);
344 toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
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);
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);
357 RunPendingMessages();
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);
365 EXPECT_TRUE(toplevel->HasCapture());
366 EXPECT_TRUE(child1->HasCapture());
367 EXPECT_FALSE(child2->HasCapture());
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);
373 EXPECT_FALSE(toplevel->HasCapture());
374 EXPECT_FALSE(child1->HasCapture());
375 EXPECT_FALSE(child2->HasCapture());
377 RunPendingMessages();
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());
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());
396 toplevel->CloseNow();
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();
404 toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
406 MouseView* view = new MouseView();
407 view->SetBounds(90, 90, 10, 10);
408 toplevel->GetRootView()->AddChildView(view);
411 RunPendingMessages();
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,
417 toplevel->OnMouseEvent(&moved_out);
418 EXPECT_EQ(0, view->EnteredCalls());
419 EXPECT_EQ(0, view->ExitedCalls());
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,
425 toplevel->OnMouseEvent(&moved_over);
426 EXPECT_EQ(1, view->EnteredCalls());
427 EXPECT_EQ(0, view->ExitedCalls());
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,
433 toplevel->OnMouseEvent(&moved_resizer);
434 EXPECT_EQ(0, view->EnteredCalls());
435 EXPECT_EQ(1, view->ExitedCalls());
437 // Move onto the view again.
438 toplevel->OnMouseEvent(&moved_over);
439 EXPECT_EQ(1, view->EnteredCalls());
440 EXPECT_EQ(0, view->ExitedCalls());
442 RunPendingMessages();
444 toplevel->CloseNow();
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 {
458 WidgetActivationTest()
461 virtual ~WidgetActivationTest() {}
463 virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE {
467 bool active() const { return active_; }
472 DISALLOW_COPY_AND_ASSIGN(WidgetActivationTest);
475 // Tests whether the widget only becomes active when the underlying window
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);
485 init_params.bounds = gfx::Rect(0, 0, 200, 200);
486 widget1.Init(init_params);
488 EXPECT_EQ(true, widget1.active());
490 WidgetActivationTest widget2;
491 #if defined(USE_AURA)
492 init_params.native_widget = new DesktopNativeWidgetAura(&widget2);
494 widget2.Init(init_params);
496 EXPECT_EQ(true, widget2.active());
497 EXPECT_EQ(false, widget1.active());
499 HWND win32_native_window1 = HWNDForWidget(&widget1);
500 EXPECT_TRUE(::IsWindow(win32_native_window1));
502 ::SendMessage(win32_native_window1, WM_NCACTIVATE, 1, 0);
503 EXPECT_EQ(false, widget1.active());
504 EXPECT_EQ(true, widget2.active());
506 ::SetActiveWindow(win32_native_window1);
507 EXPECT_EQ(true, widget1.active());
508 EXPECT_EQ(false, widget2.active());
512 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
513 // Provides functionality to create a window modal dialog.
514 class ModalDialogDelegate : public DialogDelegateView {
516 explicit ModalDialogDelegate(ui::ModalType type) : type_(type) {}
517 virtual ~ModalDialogDelegate() {}
519 // WidgetDelegate overrides.
520 virtual ui::ModalType GetModalType() const OVERRIDE {
527 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
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
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();
546 aura::Window* top_level_window = top_level_widget.GetNativeWindow();
547 EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
548 top_level_window)->GetFocusedWindow());
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);
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());
563 modal_dialog_widget->CloseNow();
564 EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
565 top_level_window)->GetFocusedWindow());
566 top_level_widget.CloseNow();
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();
583 aura::Window* top_level_window = top_level_widget.GetNativeWindow();
584 EXPECT_EQ(top_level_window, aura::client::GetFocusClient(
585 top_level_window)->GetFocusedWindow());
587 EXPECT_FALSE(top_level_window->HasCapture());
588 top_level_window->SetCapture();
589 EXPECT_TRUE(top_level_window->HasCapture());
591 // Create a modal dialog.
592 ModalDialogDelegate* dialog_delegate =
593 new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
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();
600 EXPECT_FALSE(top_level_window->HasCapture());
602 modal_dialog_widget->CloseNow();
603 top_level_widget.CloseNow();
610 // Used to veirfy OnMouseCaptureLost() has been invoked.
611 class CaptureLostTrackingWidget : public Widget {
613 CaptureLostTrackingWidget() : got_capture_lost_(false) {}
614 virtual ~CaptureLostTrackingWidget() {}
616 bool GetAndClearGotCaptureLost() {
617 bool value = got_capture_lost_;
618 got_capture_lost_ = false;
623 virtual void OnMouseCaptureLost() OVERRIDE {
624 got_capture_lost_ = true;
625 Widget::OnMouseCaptureLost();
629 bool got_capture_lost_;
631 DISALLOW_COPY_AND_ASSIGN(CaptureLostTrackingWidget);
636 class WidgetCaptureTest : public ViewsTestBase {
638 WidgetCaptureTest() {
641 virtual ~WidgetCaptureTest() {
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,
652 params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
653 widget1.Init(params1);
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,
662 widget2.Init(params2);
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());
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());
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());
688 NativeWidget* CreateNativeWidget(bool create_desktop_native_widget,
690 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
691 if (create_desktop_native_widget)
692 return new DesktopNativeWidgetAura(widget);
697 DISALLOW_COPY_AND_ASSIGN(WidgetCaptureTest);
700 // See description in TestCapture().
701 TEST_F(WidgetCaptureTest, Capture) {
705 #if defined(USE_AURA) && !defined(OS_LINUX)
706 // See description in TestCapture(). Creates DesktopNativeWidget.
707 TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
712 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
715 // Used to veirfy OnMouseEvent() has been invoked.
716 class MouseEventTrackingWidget : public Widget {
718 MouseEventTrackingWidget() : got_mouse_event_(false) {}
719 virtual ~MouseEventTrackingWidget() {}
721 bool GetAndClearGotMouseEvent() {
722 bool value = got_mouse_event_;
723 got_mouse_event_ = false;
728 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
729 got_mouse_event_ = true;
730 Widget::OnMouseEvent(event);
734 bool got_mouse_event_;
736 DISALLOW_COPY_AND_ASSIGN(MouseEventTrackingWidget);
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
746 #define MAYBE_MouseEventDispatchedToRightWindow \
747 MouseEventDispatchedToRightWindow
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);
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);
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());
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());