1 // Copyright (c) 2012 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 "ash/drag_drop/drag_drop_controller.h" 6 7 #include "ash/drag_drop/drag_drop_tracker.h" 8 #include "ash/drag_drop/drag_image_view.h" 9 #include "ash/shell.h" 10 #include "ash/test/ash_test_base.h" 11 #include "base/command_line.h" 12 #include "base/location.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "ui/aura/client/capture_client.h" 15 #include "ui/aura/root_window.h" 16 #include "ui/aura/test/event_generator.h" 17 #include "ui/base/animation/linear_animation.h" 18 #include "ui/base/clipboard/clipboard.h" 19 #include "ui/base/clipboard/scoped_clipboard_writer.h" 20 #include "ui/base/dragdrop/drag_drop_types.h" 21 #include "ui/base/dragdrop/drag_utils.h" 22 #include "ui/base/dragdrop/os_exchange_data.h" 23 #include "ui/base/events/event.h" 24 #include "ui/base/events/event_utils.h" 25 #include "ui/base/gestures/gesture_types.h" 26 #include "ui/base/ui_base_switches.h" 27 #include "ui/gfx/image/image_skia_rep.h" 28 #include "ui/views/test/test_views_delegate.h" 29 #include "ui/views/view.h" 30 #include "ui/views/views_delegate.h" 31 #include "ui/views/widget/native_widget_aura.h" 32 #include "ui/views/widget/native_widget_delegate.h" 33 #include "ui/views/widget/widget.h" 34 35 namespace ash { 36 namespace test { 37 38 namespace { 39 40 // A simple view that makes sure RunShellDrag is invoked on mouse drag. 41 class DragTestView : public views::View { 42 public: 43 DragTestView() : views::View() { 44 Reset(); 45 } 46 47 void Reset() { 48 num_drag_enters_ = 0; 49 num_drag_exits_ = 0; 50 num_drag_updates_ = 0; 51 num_drops_ = 0; 52 drag_done_received_ = false; 53 long_tap_received_ = false; 54 } 55 56 int VerticalDragThreshold() { 57 return views::View::GetVerticalDragThreshold(); 58 } 59 60 int HorizontalDragThreshold() { 61 return views::View::GetHorizontalDragThreshold(); 62 } 63 64 int num_drag_enters_; 65 int num_drag_exits_; 66 int num_drag_updates_; 67 int num_drops_; 68 bool drag_done_received_; 69 bool long_tap_received_; 70 71 private: 72 // View overrides: 73 virtual int GetDragOperations(const gfx::Point& press_pt) OVERRIDE { 74 return ui::DragDropTypes::DRAG_COPY; 75 } 76 77 virtual void WriteDragData(const gfx::Point& p, 78 OSExchangeData* data) OVERRIDE { 79 data->SetString(UTF8ToUTF16("I am being dragged")); 80 gfx::ImageSkiaRep image_rep(gfx::Size(10, 20), ui::SCALE_FACTOR_100P); 81 gfx::ImageSkia image_skia(image_rep); 82 83 drag_utils::SetDragImageOnDataObject( 84 image_skia, image_skia.size(), gfx::Vector2d(), data); 85 } 86 87 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE { 88 return true; 89 } 90 91 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 92 if (event->type() == ui::ET_GESTURE_LONG_TAP) 93 long_tap_received_ = true; 94 return; 95 } 96 97 virtual bool GetDropFormats( 98 int* formats, 99 std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE { 100 *formats = ui::OSExchangeData::STRING; 101 return true; 102 } 103 104 virtual bool CanDrop(const OSExchangeData& data) OVERRIDE { 105 return true; 106 } 107 108 virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE { 109 num_drag_enters_++; 110 } 111 112 virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE { 113 num_drag_updates_++; 114 return ui::DragDropTypes::DRAG_COPY; 115 } 116 117 virtual void OnDragExited() OVERRIDE { 118 num_drag_exits_++; 119 } 120 121 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE { 122 num_drops_++; 123 return ui::DragDropTypes::DRAG_COPY; 124 } 125 126 virtual void OnDragDone() OVERRIDE { 127 drag_done_received_ = true; 128 } 129 130 DISALLOW_COPY_AND_ASSIGN(DragTestView); 131 }; 132 133 class CompletableLinearAnimation : public ui::LinearAnimation { 134 public: 135 CompletableLinearAnimation(int duration, 136 int frame_rate, 137 ui::AnimationDelegate* delegate) 138 : ui::LinearAnimation(duration, frame_rate, delegate), 139 duration_(duration) { 140 } 141 142 void Complete() { 143 Step(start_time() + base::TimeDelta::FromMilliseconds(duration_)); 144 } 145 146 private: 147 int duration_; 148 }; 149 150 class TestDragDropController : public internal::DragDropController { 151 public: 152 TestDragDropController() : internal::DragDropController() { 153 Reset(); 154 } 155 156 void Reset() { 157 drag_start_received_ = false; 158 num_drag_updates_ = 0; 159 drop_received_ = false; 160 drag_canceled_ = false; 161 drag_string_.clear(); 162 } 163 164 virtual int StartDragAndDrop( 165 const ui::OSExchangeData& data, 166 aura::RootWindow* root_window, 167 aura::Window* source_window, 168 const gfx::Point& location, 169 int operation, 170 ui::DragDropTypes::DragEventSource source) OVERRIDE { 171 drag_start_received_ = true; 172 data.GetString(&drag_string_); 173 return DragDropController::StartDragAndDrop( 174 data, root_window, source_window, location, operation, source); 175 } 176 177 virtual void DragUpdate(aura::Window* target, 178 const ui::LocatedEvent& event) OVERRIDE { 179 DragDropController::DragUpdate(target, event); 180 num_drag_updates_++; 181 } 182 183 virtual void Drop(aura::Window* target, 184 const ui::LocatedEvent& event) OVERRIDE { 185 DragDropController::Drop(target, event); 186 drop_received_ = true; 187 } 188 189 virtual void DragCancel() OVERRIDE { 190 DragDropController::DragCancel(); 191 drag_canceled_ = true; 192 } 193 194 virtual ui::LinearAnimation* CreateCancelAnimation( 195 int duration, 196 int frame_rate, 197 ui::AnimationDelegate* delegate) OVERRIDE { 198 return new CompletableLinearAnimation(duration, frame_rate, delegate); 199 } 200 201 virtual void DoDragCancel(int animation_duration_ms) OVERRIDE { 202 DragDropController::DoDragCancel(animation_duration_ms); 203 drag_canceled_ = true; 204 } 205 206 bool drag_start_received_; 207 int num_drag_updates_; 208 bool drop_received_; 209 bool drag_canceled_; 210 base::string16 drag_string_; 211 212 private: 213 DISALLOW_COPY_AND_ASSIGN(TestDragDropController); 214 }; 215 216 class TestNativeWidgetAura : public views::NativeWidgetAura { 217 public: 218 explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate* delegate) 219 : NativeWidgetAura(delegate), 220 check_if_capture_lost_(false) { 221 } 222 223 void set_check_if_capture_lost(bool value) { 224 check_if_capture_lost_ = value; 225 } 226 227 virtual void OnCaptureLost() OVERRIDE { 228 DCHECK(!check_if_capture_lost_); 229 views::NativeWidgetAura::OnCaptureLost(); 230 } 231 232 private: 233 bool check_if_capture_lost_; 234 235 DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura); 236 }; 237 238 // TODO(sky): this is for debugging, remove when track down failure. 239 void SetCheckIfCaptureLost(views::Widget* widget, bool value) { 240 // On Windows, the DCHECK triggers when running on bot or locally through RDP, 241 // but not when logged in locally. 242 #if !defined(OS_WIN) 243 static_cast<TestNativeWidgetAura*>(widget->native_widget())-> 244 set_check_if_capture_lost(value); 245 #endif 246 } 247 248 views::Widget* CreateNewWidget() { 249 views::Widget* widget = new views::Widget; 250 views::Widget::InitParams params; 251 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; 252 params.accept_events = true; 253 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 254 params.parent = Shell::GetPrimaryRootWindow(); 255 params.child = true; 256 params.native_widget = new TestNativeWidgetAura(widget); 257 widget->Init(params); 258 widget->Show(); 259 return widget; 260 } 261 262 void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) { 263 if (!widget->GetContentsView()) { 264 views::View* contents_view = new views::View; 265 widget->SetContentsView(contents_view); 266 } 267 268 views::View* contents_view = widget->GetContentsView(); 269 contents_view->AddChildView(view); 270 view->SetBounds(contents_view->width(), 0, 100, 100); 271 gfx::Rect contents_view_bounds = contents_view->bounds(); 272 contents_view_bounds.Union(view->bounds()); 273 contents_view->SetBoundsRect(contents_view_bounds); 274 widget->SetBounds(contents_view_bounds); 275 } 276 277 void DispatchGesture(ui::EventType gesture_type, gfx::Point location) { 278 ui::GestureEvent gesture_event( 279 gesture_type, 280 location.x(), 281 location.y(), 282 0, 283 ui::EventTimeForNow(), 284 ui::GestureEventDetails(gesture_type, 0, 0), 285 1); 286 Shell::GetPrimaryRootWindow()->DispatchGestureEvent(&gesture_event); 287 } 288 289 bool IsGestureEventType(ui::EventType type) { 290 switch (type) { 291 case ui::ET_GESTURE_SCROLL_BEGIN: 292 case ui::ET_GESTURE_SCROLL_END: 293 case ui::ET_GESTURE_SCROLL_UPDATE: 294 case ui::ET_GESTURE_TAP: 295 case ui::ET_GESTURE_TAP_CANCEL: 296 case ui::ET_GESTURE_TAP_DOWN: 297 case ui::ET_GESTURE_BEGIN: 298 case ui::ET_GESTURE_END: 299 case ui::ET_GESTURE_TWO_FINGER_TAP: 300 case ui::ET_GESTURE_PINCH_BEGIN: 301 case ui::ET_GESTURE_PINCH_END: 302 case ui::ET_GESTURE_PINCH_UPDATE: 303 case ui::ET_GESTURE_LONG_PRESS: 304 case ui::ET_GESTURE_LONG_TAP: 305 case ui::ET_GESTURE_MULTIFINGER_SWIPE: 306 case ui::ET_SCROLL_FLING_CANCEL: 307 case ui::ET_SCROLL_FLING_START: 308 return true; 309 default: 310 break; 311 } 312 return false; 313 } 314 315 } // namespace 316 317 class DragDropControllerTest : public AshTestBase { 318 public: 319 DragDropControllerTest() : AshTestBase() {} 320 virtual ~DragDropControllerTest() {} 321 322 virtual void SetUp() OVERRIDE { 323 AshTestBase::SetUp(); 324 drag_drop_controller_.reset(new TestDragDropController); 325 drag_drop_controller_->set_should_block_during_drag_drop(false); 326 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), 327 drag_drop_controller_.get()); 328 views_delegate_.reset(new views::TestViewsDelegate); 329 } 330 331 virtual void TearDown() OVERRIDE { 332 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL); 333 drag_drop_controller_.reset(); 334 AshTestBase::TearDown(); 335 } 336 337 void UpdateDragData(ui::OSExchangeData* data) { 338 drag_drop_controller_->drag_data_ = data; 339 } 340 341 aura::Window* GetDragWindow() { 342 return drag_drop_controller_->drag_window_; 343 } 344 345 aura::Window* GetDragSourceWindow() { 346 return drag_drop_controller_->drag_source_window_; 347 } 348 349 void SetDragSourceWindow(aura::Window* drag_source_window) { 350 drag_drop_controller_->drag_source_window_ = drag_source_window; 351 drag_source_window->AddObserver(drag_drop_controller_.get()); 352 } 353 354 aura::Window* GetDragImageWindow() { 355 return drag_drop_controller_->drag_image_.get() ? 356 drag_drop_controller_->drag_image_->GetWidget()->GetNativeWindow() : 357 NULL; 358 } 359 360 internal::DragDropTracker* drag_drop_tracker() { 361 return drag_drop_controller_->drag_drop_tracker_.get(); 362 } 363 364 void CompleteCancelAnimation() { 365 CompletableLinearAnimation* animation = 366 static_cast<CompletableLinearAnimation*>( 367 drag_drop_controller_->cancel_animation_.get()); 368 animation->Complete(); 369 } 370 371 protected: 372 scoped_ptr<TestDragDropController> drag_drop_controller_; 373 scoped_ptr<views::TestViewsDelegate> views_delegate_; 374 375 private: 376 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest); 377 }; 378 379 // TODO(win_aura) http://crbug.com/154081 380 #if defined(OS_WIN) 381 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest 382 #else 383 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest 384 #endif 385 TEST_F(DragDropControllerTest, MAYBE_DragDropInSingleViewTest) { 386 scoped_ptr<views::Widget> widget(CreateNewWidget()); 387 DragTestView* drag_view = new DragTestView; 388 AddViewToWidgetAndResize(widget.get(), drag_view); 389 ui::OSExchangeData data; 390 data.SetString(UTF8ToUTF16("I am being dragged")); 391 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 392 widget->GetNativeView()); 393 generator.PressLeftButton(); 394 395 int num_drags = 17; 396 SetCheckIfCaptureLost(widget.get(), true); 397 for (int i = 0; i < num_drags; ++i) { 398 // Because we are not doing a blocking drag and drop, the original 399 // OSDragExchangeData object is lost as soon as we return from the drag 400 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 401 // drag_data_ to a fake drag data object that we created. 402 if (i > 0) 403 UpdateDragData(&data); 404 // 7 comes from views::View::GetVerticalDragThreshold()). 405 if (i >= 7) 406 SetCheckIfCaptureLost(widget.get(), false); 407 408 generator.MoveMouseBy(0, 1); 409 410 // Execute any scheduled draws to process deferred mouse events. 411 RunAllPendingInMessageLoop(); 412 } 413 414 generator.ReleaseLeftButton(); 415 416 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 417 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 418 drag_drop_controller_->num_drag_updates_); 419 EXPECT_TRUE(drag_drop_controller_->drop_received_); 420 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 421 drag_drop_controller_->drag_string_); 422 423 EXPECT_EQ(1, drag_view->num_drag_enters_); 424 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 425 drag_view->num_drag_updates_); 426 EXPECT_EQ(1, drag_view->num_drops_); 427 EXPECT_EQ(0, drag_view->num_drag_exits_); 428 EXPECT_TRUE(drag_view->drag_done_received_); 429 } 430 431 TEST_F(DragDropControllerTest, DragDropWithZeroDragUpdates) { 432 scoped_ptr<views::Widget> widget(CreateNewWidget()); 433 DragTestView* drag_view = new DragTestView; 434 AddViewToWidgetAndResize(widget.get(), drag_view); 435 ui::OSExchangeData data; 436 data.SetString(UTF8ToUTF16("I am being dragged")); 437 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 438 widget->GetNativeView()); 439 generator.PressLeftButton(); 440 441 int num_drags = drag_view->VerticalDragThreshold() + 1; 442 for (int i = 0; i < num_drags; ++i) { 443 // Because we are not doing a blocking drag and drop, the original 444 // OSDragExchangeData object is lost as soon as we return from the drag 445 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 446 // drag_data_ to a fake drag data object that we created. 447 if (i > 0) 448 UpdateDragData(&data); 449 generator.MoveMouseBy(0, 1); 450 } 451 452 UpdateDragData(&data); 453 454 generator.ReleaseLeftButton(); 455 456 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 457 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1, 458 drag_drop_controller_->num_drag_updates_); 459 EXPECT_TRUE(drag_drop_controller_->drop_received_); 460 461 EXPECT_EQ(1, drag_view->num_drag_enters_); 462 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1, 463 drag_view->num_drag_updates_); 464 EXPECT_EQ(1, drag_view->num_drops_); 465 EXPECT_EQ(0, drag_view->num_drag_exits_); 466 EXPECT_TRUE(drag_view->drag_done_received_); 467 } 468 469 // TODO(win_aura) http://crbug.com/154081 470 #if defined(OS_WIN) 471 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest 472 #else 473 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest 474 #endif 475 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsSingleWidgetTest) { 476 scoped_ptr<views::Widget> widget(CreateNewWidget()); 477 DragTestView* drag_view1 = new DragTestView; 478 AddViewToWidgetAndResize(widget.get(), drag_view1); 479 DragTestView* drag_view2 = new DragTestView; 480 AddViewToWidgetAndResize(widget.get(), drag_view2); 481 482 ui::OSExchangeData data; 483 data.SetString(UTF8ToUTF16("I am being dragged")); 484 485 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); 486 generator.MoveMouseRelativeTo(widget->GetNativeView(), 487 drag_view1->bounds().CenterPoint()); 488 generator.PressLeftButton(); 489 490 int num_drags = drag_view1->width(); 491 for (int i = 0; i < num_drags; ++i) { 492 // Because we are not doing a blocking drag and drop, the original 493 // OSDragExchangeData object is lost as soon as we return from the drag 494 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 495 // drag_data_ to a fake drag data object that we created. 496 if (i > 0) 497 UpdateDragData(&data); 498 generator.MoveMouseBy(1, 0); 499 500 // Execute any scheduled draws to process deferred mouse events. 501 RunAllPendingInMessageLoop(); 502 } 503 504 generator.ReleaseLeftButton(); 505 506 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 507 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(), 508 drag_drop_controller_->num_drag_updates_); 509 EXPECT_TRUE(drag_drop_controller_->drop_received_); 510 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 511 drag_drop_controller_->drag_string_); 512 513 EXPECT_EQ(1, drag_view1->num_drag_enters_); 514 int num_expected_updates = drag_view1->bounds().width() - 515 drag_view1->bounds().CenterPoint().x() - 2; 516 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(), 517 drag_view1->num_drag_updates_); 518 EXPECT_EQ(0, drag_view1->num_drops_); 519 EXPECT_EQ(1, drag_view1->num_drag_exits_); 520 EXPECT_TRUE(drag_view1->drag_done_received_); 521 522 EXPECT_EQ(1, drag_view2->num_drag_enters_); 523 num_expected_updates = num_drags - num_expected_updates - 1; 524 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_); 525 EXPECT_EQ(1, drag_view2->num_drops_); 526 EXPECT_EQ(0, drag_view2->num_drag_exits_); 527 EXPECT_FALSE(drag_view2->drag_done_received_); 528 } 529 530 // TODO(win_aura) http://crbug.com/154081 531 #if defined(OS_WIN) 532 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest 533 #else 534 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest 535 #endif 536 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest) { 537 scoped_ptr<views::Widget> widget1(CreateNewWidget()); 538 DragTestView* drag_view1 = new DragTestView; 539 AddViewToWidgetAndResize(widget1.get(), drag_view1); 540 scoped_ptr<views::Widget> widget2(CreateNewWidget()); 541 DragTestView* drag_view2 = new DragTestView; 542 AddViewToWidgetAndResize(widget2.get(), drag_view2); 543 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen(); 544 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen(); 545 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0, 546 widget2_bounds.width(), widget2_bounds.height())); 547 548 ui::OSExchangeData data; 549 data.SetString(UTF8ToUTF16("I am being dragged")); 550 551 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 552 widget1->GetNativeView()); 553 generator.PressLeftButton(); 554 555 int num_drags = drag_view1->width(); 556 for (int i = 0; i < num_drags; ++i) { 557 // Because we are not doing a blocking drag and drop, the original 558 // OSDragExchangeData object is lost as soon as we return from the drag 559 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 560 // drag_data_ to a fake drag data object that we created. 561 if (i > 0) 562 UpdateDragData(&data); 563 generator.MoveMouseBy(1, 0); 564 565 // Execute any scheduled draws to process deferred mouse events. 566 RunAllPendingInMessageLoop(); 567 } 568 569 generator.ReleaseLeftButton(); 570 571 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 572 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(), 573 drag_drop_controller_->num_drag_updates_); 574 EXPECT_TRUE(drag_drop_controller_->drop_received_); 575 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 576 drag_drop_controller_->drag_string_); 577 578 EXPECT_EQ(1, drag_view1->num_drag_enters_); 579 int num_expected_updates = drag_view1->bounds().width() - 580 drag_view1->bounds().CenterPoint().x() - 2; 581 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(), 582 drag_view1->num_drag_updates_); 583 EXPECT_EQ(0, drag_view1->num_drops_); 584 EXPECT_EQ(1, drag_view1->num_drag_exits_); 585 EXPECT_TRUE(drag_view1->drag_done_received_); 586 587 EXPECT_EQ(1, drag_view2->num_drag_enters_); 588 num_expected_updates = num_drags - num_expected_updates - 1; 589 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_); 590 EXPECT_EQ(1, drag_view2->num_drops_); 591 EXPECT_EQ(0, drag_view2->num_drag_exits_); 592 EXPECT_FALSE(drag_view2->drag_done_received_); 593 } 594 595 // TODO(win_aura) http://crbug.com/154081 596 #if defined(OS_WIN) 597 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest 598 #else 599 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest 600 #endif 601 TEST_F(DragDropControllerTest, MAYBE_ViewRemovedWhileInDragDropTest) { 602 scoped_ptr<views::Widget> widget(CreateNewWidget()); 603 scoped_ptr<DragTestView> drag_view(new DragTestView); 604 AddViewToWidgetAndResize(widget.get(), drag_view.get()); 605 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint(); 606 ui::OSExchangeData data; 607 data.SetString(UTF8ToUTF16("I am being dragged")); 608 609 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); 610 generator.MoveMouseToCenterOf(widget->GetNativeView()); 611 generator.PressLeftButton(); 612 613 int num_drags_1 = 17; 614 for (int i = 0; i < num_drags_1; ++i) { 615 // Because we are not doing a blocking drag and drop, the original 616 // OSDragExchangeData object is lost as soon as we return from the drag 617 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 618 // drag_data_ to a fake drag data object that we created. 619 if (i > 0) 620 UpdateDragData(&data); 621 generator.MoveMouseBy(0, 1); 622 623 // Execute any scheduled draws to process deferred mouse events. 624 RunAllPendingInMessageLoop(); 625 } 626 627 drag_view->parent()->RemoveChildView(drag_view.get()); 628 // View has been removed. We will not get any of the following drag updates. 629 int num_drags_2 = 23; 630 for (int i = 0; i < num_drags_2; ++i) { 631 UpdateDragData(&data); 632 generator.MoveMouseBy(0, 1); 633 634 // Execute any scheduled draws to process deferred mouse events. 635 RunAllPendingInMessageLoop(); 636 } 637 638 generator.ReleaseLeftButton(); 639 640 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 641 EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(), 642 drag_drop_controller_->num_drag_updates_); 643 EXPECT_TRUE(drag_drop_controller_->drop_received_); 644 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 645 drag_drop_controller_->drag_string_); 646 647 EXPECT_EQ(1, drag_view->num_drag_enters_); 648 EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(), 649 drag_view->num_drag_updates_); 650 EXPECT_EQ(0, drag_view->num_drops_); 651 EXPECT_EQ(0, drag_view->num_drag_exits_); 652 EXPECT_TRUE(drag_view->drag_done_received_); 653 } 654 655 TEST_F(DragDropControllerTest, DragLeavesClipboardAloneTest) { 656 ui::Clipboard* cb = ui::Clipboard::GetForCurrentThread(); 657 std::string clip_str("I am on the clipboard"); 658 { 659 // We first copy some text to the clipboard. 660 ui::ScopedClipboardWriter scw(cb, ui::Clipboard::BUFFER_STANDARD); 661 scw.WriteText(ASCIIToUTF16(clip_str)); 662 } 663 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), 664 ui::Clipboard::BUFFER_STANDARD)); 665 666 scoped_ptr<views::Widget> widget(CreateNewWidget()); 667 DragTestView* drag_view = new DragTestView; 668 AddViewToWidgetAndResize(widget.get(), drag_view); 669 670 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 671 widget->GetNativeView()); 672 ui::OSExchangeData data; 673 std::string data_str("I am being dragged"); 674 data.SetString(ASCIIToUTF16(data_str)); 675 676 generator.PressLeftButton(); 677 generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1); 678 679 // Execute any scheduled draws to process deferred mouse events. 680 RunAllPendingInMessageLoop(); 681 682 // Verify the clipboard contents haven't changed 683 std::string result; 684 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), 685 ui::Clipboard::BUFFER_STANDARD)); 686 cb->ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &result); 687 EXPECT_EQ(clip_str, result); 688 // Destory the clipboard here because ash doesn't delete it. 689 // crbug.com/158150. 690 ui::Clipboard::DestroyClipboardForCurrentThread(); 691 } 692 693 TEST_F(DragDropControllerTest, WindowDestroyedDuringDragDrop) { 694 scoped_ptr<views::Widget> widget(CreateNewWidget()); 695 DragTestView* drag_view = new DragTestView; 696 AddViewToWidgetAndResize(widget.get(), drag_view); 697 aura::Window* window = widget->GetNativeView(); 698 699 ui::OSExchangeData data; 700 data.SetString(UTF8ToUTF16("I am being dragged")); 701 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 702 widget->GetNativeView()); 703 generator.PressLeftButton(); 704 705 int num_drags = 17; 706 for (int i = 0; i < num_drags; ++i) { 707 // Because we are not doing a blocking drag and drop, the original 708 // OSDragExchangeData object is lost as soon as we return from the drag 709 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 710 // drag_data_ to a fake drag data object that we created. 711 if (i > 0) 712 UpdateDragData(&data); 713 generator.MoveMouseBy(0, 1); 714 715 // Execute any scheduled draws to process deferred mouse events. 716 RunAllPendingInMessageLoop(); 717 718 if (i > drag_view->VerticalDragThreshold()) 719 EXPECT_EQ(window, GetDragWindow()); 720 } 721 722 widget->CloseNow(); 723 EXPECT_FALSE(GetDragWindow()); 724 725 num_drags = 23; 726 for (int i = 0; i < num_drags; ++i) { 727 if (i > 0) 728 UpdateDragData(&data); 729 generator.MoveMouseBy(0, 1); 730 // We should not crash here. 731 } 732 733 generator.ReleaseLeftButton(); 734 735 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 736 EXPECT_TRUE(drag_drop_controller_->drop_received_); 737 } 738 739 TEST_F(DragDropControllerTest, SyntheticEventsDuringDragDrop) { 740 scoped_ptr<views::Widget> widget(CreateNewWidget()); 741 DragTestView* drag_view = new DragTestView; 742 AddViewToWidgetAndResize(widget.get(), drag_view); 743 ui::OSExchangeData data; 744 data.SetString(UTF8ToUTF16("I am being dragged")); 745 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 746 widget->GetNativeView()); 747 generator.PressLeftButton(); 748 749 int num_drags = 17; 750 for (int i = 0; i < num_drags; ++i) { 751 // Because we are not doing a blocking drag and drop, the original 752 // OSDragExchangeData object is lost as soon as we return from the drag 753 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 754 // drag_data_ to a fake drag data object that we created. 755 if (i > 0) 756 UpdateDragData(&data); 757 generator.MoveMouseBy(0, 1); 758 759 // We send a unexpected mouse move event. Note that we cannot use 760 // EventGenerator since it implicitly turns these into mouse drag events. 761 // The DragDropController should simply ignore these events. 762 gfx::Point mouse_move_location = drag_view->bounds().CenterPoint(); 763 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location, 764 mouse_move_location, 0); 765 Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->OnHostMouseEvent( 766 &mouse_move); 767 } 768 769 generator.ReleaseLeftButton(); 770 771 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 772 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 773 drag_drop_controller_->num_drag_updates_); 774 EXPECT_TRUE(drag_drop_controller_->drop_received_); 775 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 776 drag_drop_controller_->drag_string_); 777 778 EXPECT_EQ(1, drag_view->num_drag_enters_); 779 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 780 drag_view->num_drag_updates_); 781 EXPECT_EQ(1, drag_view->num_drops_); 782 EXPECT_EQ(0, drag_view->num_drag_exits_); 783 EXPECT_TRUE(drag_view->drag_done_received_); 784 } 785 786 // TODO(win_aura) http://crbug.com/154081 787 #if defined(OS_WIN) 788 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop 789 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop 790 #else 791 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop 792 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop 793 #endif 794 TEST_F(DragDropControllerTest, MAYBE_PressingEscapeCancelsDragDrop) { 795 scoped_ptr<views::Widget> widget(CreateNewWidget()); 796 DragTestView* drag_view = new DragTestView; 797 AddViewToWidgetAndResize(widget.get(), drag_view); 798 ui::OSExchangeData data; 799 data.SetString(UTF8ToUTF16("I am being dragged")); 800 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 801 widget->GetNativeView()); 802 generator.PressLeftButton(); 803 804 int num_drags = 17; 805 for (int i = 0; i < num_drags; ++i) { 806 // Because we are not doing a blocking drag and drop, the original 807 // OSDragExchangeData object is lost as soon as we return from the drag 808 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 809 // drag_data_ to a fake drag data object that we created. 810 if (i > 0) 811 UpdateDragData(&data); 812 generator.MoveMouseBy(0, 1); 813 814 // Execute any scheduled draws to process deferred mouse events. 815 RunAllPendingInMessageLoop(); 816 } 817 818 generator.PressKey(ui::VKEY_ESCAPE, 0); 819 820 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 821 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 822 drag_drop_controller_->num_drag_updates_); 823 EXPECT_FALSE(drag_drop_controller_->drop_received_); 824 EXPECT_TRUE(drag_drop_controller_->drag_canceled_); 825 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 826 drag_drop_controller_->drag_string_); 827 828 EXPECT_EQ(1, drag_view->num_drag_enters_); 829 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 830 drag_view->num_drag_updates_); 831 EXPECT_EQ(0, drag_view->num_drops_); 832 EXPECT_EQ(1, drag_view->num_drag_exits_); 833 EXPECT_TRUE(drag_view->drag_done_received_); 834 } 835 836 TEST_F(DragDropControllerTest, MAYBE_CaptureLostCancelsDragDrop) { 837 scoped_ptr<views::Widget> widget(CreateNewWidget()); 838 DragTestView* drag_view = new DragTestView; 839 AddViewToWidgetAndResize(widget.get(), drag_view); 840 ui::OSExchangeData data; 841 data.SetString(UTF8ToUTF16("I am being dragged")); 842 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 843 widget->GetNativeView()); 844 generator.PressLeftButton(); 845 846 int num_drags = 17; 847 for (int i = 0; i < num_drags; ++i) { 848 // Because we are not doing a blocking drag and drop, the original 849 // OSDragExchangeData object is lost as soon as we return from the drag 850 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 851 // drag_data_ to a fake drag data object that we created. 852 if (i > 0) 853 UpdateDragData(&data); 854 generator.MoveMouseBy(0, 1); 855 856 // Execute any scheduled draws to process deferred mouse events. 857 RunAllPendingInMessageLoop(); 858 } 859 // Make sure the capture window won't handle mouse events. 860 aura::Window* capture_window = drag_drop_tracker()->capture_window(); 861 ASSERT_TRUE(!!capture_window); 862 EXPECT_EQ("0x0", capture_window->bounds().size().ToString()); 863 EXPECT_EQ(NULL, 864 capture_window->GetEventHandlerForPoint(gfx::Point())); 865 EXPECT_EQ(NULL, 866 capture_window->GetTopWindowContainingPoint(gfx::Point())); 867 868 aura::client::GetCaptureClient(widget->GetNativeView()->GetRootWindow())-> 869 SetCapture(NULL); 870 871 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 872 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 873 drag_drop_controller_->num_drag_updates_); 874 EXPECT_FALSE(drag_drop_controller_->drop_received_); 875 EXPECT_TRUE(drag_drop_controller_->drag_canceled_); 876 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 877 drag_drop_controller_->drag_string_); 878 879 EXPECT_EQ(1, drag_view->num_drag_enters_); 880 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(), 881 drag_view->num_drag_updates_); 882 EXPECT_EQ(0, drag_view->num_drops_); 883 EXPECT_EQ(1, drag_view->num_drag_exits_); 884 EXPECT_TRUE(drag_view->drag_done_received_); 885 } 886 887 TEST_F(DragDropControllerTest, TouchDragDropInMultipleWindows) { 888 CommandLine::ForCurrentProcess()->AppendSwitch( 889 switches::kEnableTouchDragDrop); 890 scoped_ptr<views::Widget> widget1(CreateNewWidget()); 891 DragTestView* drag_view1 = new DragTestView; 892 AddViewToWidgetAndResize(widget1.get(), drag_view1); 893 scoped_ptr<views::Widget> widget2(CreateNewWidget()); 894 DragTestView* drag_view2 = new DragTestView; 895 AddViewToWidgetAndResize(widget2.get(), drag_view2); 896 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen(); 897 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen(); 898 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0, 899 widget2_bounds.width(), widget2_bounds.height())); 900 901 ui::OSExchangeData data; 902 data.SetString(UTF8ToUTF16("I am being dragged")); 903 904 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 905 widget1->GetNativeView()); 906 generator.PressTouch(); 907 gfx::Point point = gfx::Rect(drag_view1->bounds()).CenterPoint(); 908 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point); 909 // Because we are not doing a blocking drag and drop, the original 910 // OSDragExchangeData object is lost as soon as we return from the drag 911 // initiation in DragDropController::StartDragAndDrop(). Hence we set the 912 // drag_data_ to a fake drag data object that we created. 913 UpdateDragData(&data); 914 gfx::Point gesture_location = point; 915 int num_drags = drag_view1->width(); 916 for (int i = 0; i < num_drags; ++i) { 917 gesture_location.Offset(1, 0); 918 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location); 919 920 // Execute any scheduled draws to process deferred mouse events. 921 RunAllPendingInMessageLoop(); 922 } 923 924 DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location); 925 926 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 927 EXPECT_EQ(num_drags, drag_drop_controller_->num_drag_updates_); 928 EXPECT_TRUE(drag_drop_controller_->drop_received_); 929 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 930 drag_drop_controller_->drag_string_); 931 932 EXPECT_EQ(1, drag_view1->num_drag_enters_); 933 int num_expected_updates = drag_view1->bounds().width() - 934 drag_view1->bounds().CenterPoint().x() - 1; 935 EXPECT_EQ(num_expected_updates, drag_view1->num_drag_updates_); 936 EXPECT_EQ(0, drag_view1->num_drops_); 937 EXPECT_EQ(1, drag_view1->num_drag_exits_); 938 EXPECT_TRUE(drag_view1->drag_done_received_); 939 940 EXPECT_EQ(1, drag_view2->num_drag_enters_); 941 num_expected_updates = num_drags - num_expected_updates; 942 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_); 943 EXPECT_EQ(1, drag_view2->num_drops_); 944 EXPECT_EQ(0, drag_view2->num_drag_exits_); 945 EXPECT_FALSE(drag_view2->drag_done_received_); 946 } 947 948 TEST_F(DragDropControllerTest, TouchDragDropCancelsOnLongTap) { 949 CommandLine::ForCurrentProcess()->AppendSwitch( 950 switches::kEnableTouchDragDrop); 951 scoped_ptr<views::Widget> widget(CreateNewWidget()); 952 DragTestView* drag_view = new DragTestView; 953 AddViewToWidgetAndResize(widget.get(), drag_view); 954 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 955 widget->GetNativeView()); 956 957 generator.PressTouch(); 958 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint(); 959 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point); 960 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point); 961 962 EXPECT_TRUE(drag_drop_controller_->drag_start_received_); 963 EXPECT_TRUE(drag_drop_controller_->drag_canceled_); 964 EXPECT_EQ(0, drag_drop_controller_->num_drag_updates_); 965 EXPECT_FALSE(drag_drop_controller_->drop_received_); 966 EXPECT_EQ(UTF8ToUTF16("I am being dragged"), 967 drag_drop_controller_->drag_string_); 968 EXPECT_EQ(0, drag_view->num_drag_enters_); 969 EXPECT_EQ(0, drag_view->num_drops_); 970 EXPECT_EQ(0, drag_view->num_drag_exits_); 971 EXPECT_TRUE(drag_view->drag_done_received_); 972 } 973 974 TEST_F(DragDropControllerTest, TouchDragDropLongTapGestureIsForwarded) { 975 CommandLine::ForCurrentProcess()->AppendSwitch( 976 switches::kEnableTouchDragDrop); 977 scoped_ptr<views::Widget> widget(CreateNewWidget()); 978 DragTestView* drag_view = new DragTestView; 979 AddViewToWidgetAndResize(widget.get(), drag_view); 980 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 981 widget->GetNativeView()); 982 983 generator.PressTouch(); 984 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint(); 985 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point); 986 987 // Since we are not running inside a nested loop, the |drag_source_window_| 988 // will get destroyed immediately. Hence we reassign it. 989 EXPECT_EQ(NULL, GetDragSourceWindow()); 990 SetDragSourceWindow(widget->GetNativeView()); 991 EXPECT_FALSE(drag_view->long_tap_received_); 992 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point); 993 CompleteCancelAnimation(); 994 EXPECT_TRUE(drag_view->long_tap_received_); 995 } 996 997 namespace { 998 999 class DragImageWindowObserver : public aura::WindowObserver { 1000 public: 1001 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 1002 window_location_on_destroying_ = window->GetBoundsInScreen().origin(); 1003 } 1004 1005 gfx::Point window_location_on_destroying() const { 1006 return window_location_on_destroying_; 1007 } 1008 1009 public: 1010 gfx::Point window_location_on_destroying_; 1011 }; 1012 1013 } 1014 1015 // Verifies the drag image moves back to the position where drag is started 1016 // across displays when drag is cancelled. 1017 TEST_F(DragDropControllerTest, DragCancelAcrossDisplays) { 1018 if (!SupportsMultipleDisplays()) 1019 return; 1020 1021 UpdateDisplay("400x400,400x400"); 1022 Shell::RootWindowList root_windows = 1023 Shell::GetInstance()->GetAllRootWindows(); 1024 for (Shell::RootWindowList::iterator iter = root_windows.begin(); 1025 iter != root_windows.end(); ++iter) { 1026 aura::client::SetDragDropClient(*iter, drag_drop_controller_.get()); 1027 } 1028 1029 ui::OSExchangeData data; 1030 data.SetString(UTF8ToUTF16("I am being dragged")); 1031 { 1032 scoped_ptr<views::Widget> widget(CreateNewWidget()); 1033 aura::Window* window = widget->GetNativeWindow(); 1034 drag_drop_controller_->StartDragAndDrop( 1035 data, 1036 window->GetRootWindow(), 1037 window, 1038 gfx::Point(5, 5), 1039 ui::DragDropTypes::DRAG_MOVE, 1040 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 1041 1042 DragImageWindowObserver observer; 1043 ASSERT_TRUE(GetDragImageWindow()); 1044 GetDragImageWindow()->AddObserver(&observer); 1045 1046 { 1047 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, 1048 gfx::Point(200, 0), 1049 gfx::Point(200, 0), 1050 ui::EF_NONE); 1051 drag_drop_controller_->DragUpdate(window, e); 1052 } 1053 { 1054 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, 1055 gfx::Point(600, 0), 1056 gfx::Point(600, 0), 1057 ui::EF_NONE); 1058 drag_drop_controller_->DragUpdate(window, e); 1059 } 1060 1061 drag_drop_controller_->DragCancel(); 1062 CompleteCancelAnimation(); 1063 1064 EXPECT_EQ("5,5", observer.window_location_on_destroying().ToString()); 1065 } 1066 1067 { 1068 scoped_ptr<views::Widget> widget(CreateNewWidget()); 1069 aura::Window* window = widget->GetNativeWindow(); 1070 drag_drop_controller_->StartDragAndDrop( 1071 data, 1072 window->GetRootWindow(), 1073 window, 1074 gfx::Point(405, 405), 1075 ui::DragDropTypes::DRAG_MOVE, 1076 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 1077 DragImageWindowObserver observer; 1078 ASSERT_TRUE(GetDragImageWindow()); 1079 GetDragImageWindow()->AddObserver(&observer); 1080 1081 { 1082 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, 1083 gfx::Point(600, 0), 1084 gfx::Point(600, 0), 1085 ui::EF_NONE); 1086 drag_drop_controller_->DragUpdate(window, e); 1087 } 1088 { 1089 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, 1090 gfx::Point(200, 0), 1091 gfx::Point(200, 0), 1092 ui::EF_NONE); 1093 drag_drop_controller_->DragUpdate(window, e); 1094 } 1095 1096 drag_drop_controller_->DragCancel(); 1097 CompleteCancelAnimation(); 1098 1099 EXPECT_EQ("405,405", observer.window_location_on_destroying().ToString()); 1100 } 1101 for (Shell::RootWindowList::iterator iter = root_windows.begin(); 1102 iter != root_windows.end(); ++iter) { 1103 aura::client::SetDragDropClient(*iter, NULL); 1104 } 1105 } 1106 1107 } // namespace test 1108 } // namespace aura 1109