OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/basictypes.h" | 5 #include "base/basictypes.h" |
| 6 #include "base/bind.h" |
| 7 #include "base/run_loop.h" |
6 #include "ui/gfx/native_widget_types.h" | 8 #include "ui/gfx/native_widget_types.h" |
| 9 #include "ui/views/test/widget_test.h" |
7 #include "ui/views/widget/widget.h" | 10 #include "ui/views/widget/widget.h" |
8 | 11 |
9 #if defined(USE_AURA) | 12 #if defined(USE_AURA) |
10 #include "ui/aura/client/activation_client.h" | 13 #include "ui/aura/client/activation_client.h" |
| 14 #include "ui/aura/env.h" |
11 #include "ui/aura/root_window.h" | 15 #include "ui/aura/root_window.h" |
12 #include "ui/views/test/views_test_base.h" | |
13 #if !defined(OS_CHROMEOS) | 16 #if !defined(OS_CHROMEOS) |
14 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" | 17 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" |
15 #endif | 18 #endif |
16 #endif | 19 #endif |
17 | 20 |
18 namespace views { | 21 namespace views { |
| 22 namespace test { |
| 23 |
| 24 namespace { |
| 25 |
| 26 // A View that closes the Widget and exits the current message-loop when it |
| 27 // receives a mouse-release event. |
| 28 class ExitLoopOnRelease : public View { |
| 29 public: |
| 30 ExitLoopOnRelease() {} |
| 31 virtual ~ExitLoopOnRelease() {} |
| 32 |
| 33 private: |
| 34 // Overridden from View: |
| 35 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE { |
| 36 GetWidget()->Close(); |
| 37 base::MessageLoop::current()->QuitNow(); |
| 38 } |
| 39 |
| 40 DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease); |
| 41 }; |
| 42 |
| 43 // A view that does a capture on gesture-begin events. |
| 44 class GestureCaptureView : public View { |
| 45 public: |
| 46 GestureCaptureView() {} |
| 47 virtual ~GestureCaptureView() {} |
| 48 |
| 49 private: |
| 50 // Overridden from View: |
| 51 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { |
| 52 if (event->type() == ui::ET_GESTURE_BEGIN) { |
| 53 GetWidget()->SetCapture(this); |
| 54 event->StopPropagation(); |
| 55 } |
| 56 } |
| 57 |
| 58 DISALLOW_COPY_AND_ASSIGN(GestureCaptureView); |
| 59 }; |
| 60 |
| 61 // A view that always processes all mouse events. |
| 62 class MouseView : public View { |
| 63 public: |
| 64 MouseView() |
| 65 : View(), |
| 66 entered_(0), |
| 67 exited_(0), |
| 68 pressed_(0) { |
| 69 } |
| 70 virtual ~MouseView() {} |
| 71 |
| 72 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE { |
| 73 pressed_++; |
| 74 return true; |
| 75 } |
| 76 |
| 77 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE { |
| 78 entered_++; |
| 79 } |
| 80 |
| 81 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE { |
| 82 exited_++; |
| 83 } |
| 84 |
| 85 // Return the number of OnMouseEntered calls and reset the counter. |
| 86 int EnteredCalls() { |
| 87 int i = entered_; |
| 88 entered_ = 0; |
| 89 return i; |
| 90 } |
| 91 |
| 92 // Return the number of OnMouseExited calls and reset the counter. |
| 93 int ExitedCalls() { |
| 94 int i = exited_; |
| 95 exited_ = 0; |
| 96 return i; |
| 97 } |
| 98 |
| 99 int pressed() const { return pressed_; } |
| 100 |
| 101 private: |
| 102 int entered_; |
| 103 int exited_; |
| 104 |
| 105 int pressed_; |
| 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(MouseView); |
| 108 }; |
| 109 |
| 110 // A View that shows a different widget, sets capture on that widget, and |
| 111 // initiates a nested message-loop when it receives a mouse-press event. |
| 112 class NestedLoopCaptureView : public View { |
| 113 public: |
| 114 explicit NestedLoopCaptureView(Widget* widget) : widget_(widget) {} |
| 115 virtual ~NestedLoopCaptureView() {} |
| 116 |
| 117 private: |
| 118 // Overridden from View: |
| 119 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE { |
| 120 // Start a nested loop. |
| 121 widget_->Show(); |
| 122 widget_->SetCapture(widget_->GetContentsView()); |
| 123 EXPECT_TRUE(widget_->HasCapture()); |
| 124 |
| 125 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
| 126 base::MessageLoop::ScopedNestableTaskAllower allow(loop); |
| 127 |
| 128 base::RunLoop run_loop; |
| 129 #if defined(USE_AURA) |
| 130 run_loop.set_dispatcher(aura::Env::GetInstance()->GetDispatcher()); |
| 131 #endif |
| 132 run_loop.Run(); |
| 133 return true; |
| 134 } |
| 135 |
| 136 Widget* widget_; |
| 137 |
| 138 DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView); |
| 139 }; |
| 140 |
| 141 } // namespace |
19 | 142 |
20 #if defined(OS_WIN) && defined(USE_AURA) | 143 #if defined(OS_WIN) && defined(USE_AURA) |
21 // Tests whether activation and focus change works correctly in Windows AURA. | 144 // Tests whether activation and focus change works correctly in Windows AURA. |
22 // We test the following:- | 145 // We test the following:- |
23 // 1. If the active aura window is correctly set when a top level widget is | 146 // 1. If the active aura window is correctly set when a top level widget is |
24 // created. | 147 // created. |
25 // 2. If the active aura window in widget 1 created above, is set to NULL when | 148 // 2. If the active aura window in widget 1 created above, is set to NULL when |
26 // another top level widget is created and focused. | 149 // another top level widget is created and focused. |
27 // 3. On focusing the native platform window for widget 1, the active aura | 150 // 3. On focusing the native platform window for widget 1, the active aura |
28 // window for widget 1 should be set and that for widget 2 should reset. | 151 // window for widget 1 should be set and that for widget 2 should reset. |
29 // TODO(ananta) | 152 // TODO(ananta) |
30 // Discuss with erg on how to write this test for linux x11 aura. | 153 // Discuss with erg on how to write this test for linux x11 aura. |
31 TEST_F(ViewsTestBase, DesktopNativeWidgetAuraActivationAndFocusTest) { | 154 TEST_F(WidgetTest, DesktopNativeWidgetAuraActivationAndFocusTest) { |
32 // Create widget 1 and expect the active window to be its window. | 155 // Create widget 1 and expect the active window to be its window. |
33 View* contents_view1 = new View; | 156 View* contents_view1 = new View; |
34 contents_view1->set_focusable(true); | 157 contents_view1->set_focusable(true); |
35 Widget widget1; | 158 Widget widget1; |
36 Widget::InitParams init_params = | 159 Widget::InitParams init_params = |
37 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 160 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
38 init_params.bounds = gfx::Rect(0, 0, 200, 200); | 161 init_params.bounds = gfx::Rect(0, 0, 200, 200); |
39 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 162 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
40 init_params.native_widget = new DesktopNativeWidgetAura(&widget1); | 163 init_params.native_widget = new DesktopNativeWidgetAura(&widget1); |
41 widget1.Init(init_params); | 164 widget1.Init(init_params); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 // Now set focus back to widget 1 and expect the active window to be its | 198 // Now set focus back to widget 1 and expect the active window to be its |
76 // window. | 199 // window. |
77 contents_view1->RequestFocus(); | 200 contents_view1->RequestFocus(); |
78 ::SetActiveWindow(root_window1->GetAcceleratedWidget()); | 201 ::SetActiveWindow(root_window1->GetAcceleratedWidget()); |
79 EXPECT_EQ(activation_client2->GetActiveWindow(), | 202 EXPECT_EQ(activation_client2->GetActiveWindow(), |
80 reinterpret_cast<aura::Window*>(NULL)); | 203 reinterpret_cast<aura::Window*>(NULL)); |
81 EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView()); | 204 EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView()); |
82 } | 205 } |
83 #endif | 206 #endif |
84 | 207 |
| 208 TEST_F(WidgetTest, CaptureAutoReset) { |
| 209 Widget* toplevel = CreateTopLevelFramelessPlatformWidget(); |
| 210 View* container = new View; |
| 211 toplevel->SetContentsView(container); |
| 212 |
| 213 EXPECT_FALSE(toplevel->HasCapture()); |
| 214 toplevel->SetCapture(NULL); |
| 215 EXPECT_TRUE(toplevel->HasCapture()); |
| 216 |
| 217 // By default, mouse release removes capture. |
| 218 gfx::Point click_location(45, 15); |
| 219 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location, |
| 220 ui::EF_LEFT_MOUSE_BUTTON); |
| 221 toplevel->OnMouseEvent(&release); |
| 222 EXPECT_FALSE(toplevel->HasCapture()); |
| 223 |
| 224 // Now a mouse release shouldn't remove capture. |
| 225 toplevel->set_auto_release_capture(false); |
| 226 toplevel->SetCapture(NULL); |
| 227 EXPECT_TRUE(toplevel->HasCapture()); |
| 228 toplevel->OnMouseEvent(&release); |
| 229 EXPECT_TRUE(toplevel->HasCapture()); |
| 230 toplevel->ReleaseCapture(); |
| 231 EXPECT_FALSE(toplevel->HasCapture()); |
| 232 |
| 233 toplevel->Close(); |
| 234 RunPendingMessages(); |
| 235 } |
| 236 |
| 237 TEST_F(WidgetTest, ResetCaptureOnGestureEnd) { |
| 238 Widget* toplevel = CreateTopLevelFramelessPlatformWidget(); |
| 239 View* container = new View; |
| 240 toplevel->SetContentsView(container); |
| 241 |
| 242 View* gesture = new GestureCaptureView; |
| 243 gesture->SetBounds(0, 0, 30, 30); |
| 244 container->AddChildView(gesture); |
| 245 |
| 246 MouseView* mouse = new MouseView; |
| 247 mouse->SetBounds(30, 0, 30, 30); |
| 248 container->AddChildView(mouse); |
| 249 |
| 250 toplevel->SetSize(gfx::Size(100, 100)); |
| 251 toplevel->Show(); |
| 252 |
| 253 // Start a gesture on |gesture|. |
| 254 ui::GestureEvent begin(ui::ET_GESTURE_BEGIN, |
| 255 15, 15, 0, base::TimeDelta(), |
| 256 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1); |
| 257 ui::GestureEvent end(ui::ET_GESTURE_END, |
| 258 15, 15, 0, base::TimeDelta(), |
| 259 ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1); |
| 260 toplevel->OnGestureEvent(&begin); |
| 261 |
| 262 // Now try to click on |mouse|. Since |gesture| will have capture, |mouse| |
| 263 // will not receive the event. |
| 264 gfx::Point click_location(45, 15); |
| 265 |
| 266 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location, |
| 267 ui::EF_LEFT_MOUSE_BUTTON); |
| 268 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location, |
| 269 ui::EF_LEFT_MOUSE_BUTTON); |
| 270 |
| 271 EXPECT_TRUE(toplevel->HasCapture()); |
| 272 |
| 273 toplevel->OnMouseEvent(&press); |
| 274 toplevel->OnMouseEvent(&release); |
| 275 EXPECT_EQ(0, mouse->pressed()); |
| 276 |
| 277 EXPECT_FALSE(toplevel->HasCapture()); |
| 278 |
| 279 // The end of the gesture should release the capture, and pressing on |mouse| |
| 280 // should now reach |mouse|. |
| 281 toplevel->OnGestureEvent(&end); |
| 282 toplevel->OnMouseEvent(&press); |
| 283 toplevel->OnMouseEvent(&release); |
| 284 EXPECT_EQ(1, mouse->pressed()); |
| 285 |
| 286 toplevel->Close(); |
| 287 RunPendingMessages(); |
| 288 } |
| 289 |
| 290 // Checks that if a mouse-press triggers a capture on a different widget (which |
| 291 // consumes the mouse-release event), then the target of the press does not have |
| 292 // capture. |
| 293 // Fails on chromium.webkit Windows bot, see crbug.com/264872. |
| 294 #if defined(OS_WIN) |
| 295 #define MAYBE_DisableCaptureWidgetFromMousePress\ |
| 296 DISABLED_CaptureWidgetFromMousePress |
| 297 #else |
| 298 #define MAYBE_DisableCaptureWidgetFromMousePress\ |
| 299 CaptureWidgetFromMousePress |
| 300 #endif |
| 301 TEST_F(WidgetTest, MAYBE_DisableCaptureWidgetFromMousePress) { |
| 302 // The test creates two widgets: |first| and |second|. |
| 303 // The View in |first| makes |second| visible, sets capture on it, and starts |
| 304 // a nested loop (like a menu does). The View in |second| terminates the |
| 305 // nested loop and closes the widget. |
| 306 // The test sends a mouse-press event to |first|, and posts a task to send a |
| 307 // release event to |second|, to make sure that the release event is |
| 308 // dispatched after the nested loop starts. |
| 309 |
| 310 Widget* first = CreateTopLevelFramelessPlatformWidget(); |
| 311 Widget* second = CreateTopLevelFramelessPlatformWidget(); |
| 312 |
| 313 View* container = new NestedLoopCaptureView(second); |
| 314 first->SetContentsView(container); |
| 315 |
| 316 second->SetContentsView(new ExitLoopOnRelease()); |
| 317 |
| 318 first->SetSize(gfx::Size(100, 100)); |
| 319 first->Show(); |
| 320 |
| 321 gfx::Point location(20, 20); |
| 322 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 323 base::Bind(&Widget::OnMouseEvent, |
| 324 base::Unretained(second), |
| 325 base::Owned(new ui::MouseEvent(ui::ET_MOUSE_RELEASED, |
| 326 location, |
| 327 location, |
| 328 ui::EF_LEFT_MOUSE_BUTTON)))); |
| 329 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location, |
| 330 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); |
| 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); |
| 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); |
| 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); |
| 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 toplevel->OnMouseEvent(&moved_out); |
| 417 EXPECT_EQ(0, view->EnteredCalls()); |
| 418 EXPECT_EQ(0, view->ExitedCalls()); |
| 419 |
| 420 // Move onto the active view. |
| 421 gfx::Point p2(95, 95); |
| 422 ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE); |
| 423 toplevel->OnMouseEvent(&moved_over); |
| 424 EXPECT_EQ(1, view->EnteredCalls()); |
| 425 EXPECT_EQ(0, view->ExitedCalls()); |
| 426 |
| 427 // Move onto the outer resizing border. |
| 428 gfx::Point p3(102, 95); |
| 429 ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE); |
| 430 toplevel->OnMouseEvent(&moved_resizer); |
| 431 EXPECT_EQ(0, view->EnteredCalls()); |
| 432 EXPECT_EQ(1, view->ExitedCalls()); |
| 433 |
| 434 // Move onto the view again. |
| 435 toplevel->OnMouseEvent(&moved_over); |
| 436 EXPECT_EQ(1, view->EnteredCalls()); |
| 437 EXPECT_EQ(0, view->ExitedCalls()); |
| 438 |
| 439 RunPendingMessages(); |
| 440 |
| 441 toplevel->CloseNow(); |
| 442 } |
| 443 |
| 444 } // namespace test |
85 } // namespace views | 445 } // namespace views |
OLD | NEW |