| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "services/ui/ws/drag_controller.h" | 5 #include "services/ui/ws/drag_controller.h" |
| 6 | 6 |
| 7 #include "services/ui/public/interfaces/cursor.mojom.h" |
| 7 #include "services/ui/ws/drag_source.h" | 8 #include "services/ui/ws/drag_source.h" |
| 8 #include "services/ui/ws/drag_target_connection.h" | 9 #include "services/ui/ws/drag_target_connection.h" |
| 9 #include "services/ui/ws/ids.h" | 10 #include "services/ui/ws/ids.h" |
| 10 #include "services/ui/ws/server_window.h" | 11 #include "services/ui/ws/server_window.h" |
| 11 #include "services/ui/ws/test_server_window_delegate.h" | 12 #include "services/ui/ws/test_server_window_delegate.h" |
| 12 #include "services/ui/ws/test_utils.h" | 13 #include "services/ui/ws/test_utils.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 14 #include "ui/events/base_event_utils.h" | 15 #include "ui/events/base_event_utils.h" |
| 15 | 16 |
| 16 namespace ui { | 17 namespace ui { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 private: | 122 private: |
| 122 DragControllerTest* parent_; | 123 DragControllerTest* parent_; |
| 123 TestServerWindowDelegate window_delegate_; | 124 TestServerWindowDelegate window_delegate_; |
| 124 ServerWindow window_; | 125 ServerWindow window_; |
| 125 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data_; | 126 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data_; |
| 126 uint32_t times_received_drag_drop_start_ = 0; | 127 uint32_t times_received_drag_drop_start_ = 0; |
| 127 | 128 |
| 128 std::queue<DragEvent> queued_callbacks_; | 129 std::queue<DragEvent> queued_callbacks_; |
| 129 }; | 130 }; |
| 130 | 131 |
| 131 class DragControllerTest : public testing::Test, public DragSource { | 132 class DragControllerTest : public testing::Test, |
| 133 public DragCursorUpdater, |
| 134 public DragSource { |
| 132 public: | 135 public: |
| 133 std::unique_ptr<DragTestWindow> BuildWindow() { | 136 std::unique_ptr<DragTestWindow> BuildWindow() { |
| 134 WindowId id(1, ++window_id_); | 137 WindowId id(1, ++window_id_); |
| 135 std::unique_ptr<DragTestWindow> p = | 138 std::unique_ptr<DragTestWindow> p = |
| 136 base::MakeUnique<DragTestWindow>(this, id); | 139 base::MakeUnique<DragTestWindow>(this, id); |
| 137 server_window_by_id_[id] = p->window(); | 140 server_window_by_id_[id] = p->window(); |
| 138 connection_by_window_[p->window()] = p.get(); | 141 connection_by_window_[p->window()] = p.get(); |
| 139 return p; | 142 return p; |
| 140 } | 143 } |
| 141 | 144 |
| 142 void StartDragOperation( | 145 void StartDragOperation( |
| 143 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data, | 146 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data, |
| 144 DragTestWindow* window, | 147 DragTestWindow* window, |
| 145 uint32_t drag_operations) { | 148 uint32_t drag_operations) { |
| 146 window->PerformOnDragDropStart(mime_data.Clone()); | 149 window->PerformOnDragDropStart(mime_data.Clone()); |
| 147 drag_operation_ = base::MakeUnique<DragController>( | 150 drag_operation_ = base::MakeUnique<DragController>( |
| 148 this, window->window(), window, PointerEvent::kMousePointerId, | 151 this, this, window->window(), window, PointerEvent::kMousePointerId, |
| 149 std::move(mime_data), drag_operations); | 152 std::move(mime_data), drag_operations); |
| 153 |
| 154 // It would be nice if we could just let the observer method fire, but it |
| 155 // fires during the constructor when we haven't assigned the unique_ptr |
| 156 // yet. |
| 157 cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor()); |
| 150 } | 158 } |
| 151 | 159 |
| 152 void DispatchDrag(DragTestWindow* window, | 160 void DispatchDrag(DragTestWindow* window, |
| 153 bool mouse_released, | 161 bool mouse_released, |
| 154 uint32_t flags, | 162 uint32_t flags, |
| 155 const gfx::Point& position) { | 163 const gfx::Point& position) { |
| 156 ui::PointerEvent event( | 164 ui::PointerEvent event( |
| 157 ui::MouseEvent(mouse_released ? ET_MOUSE_RELEASED : ET_MOUSE_PRESSED, | 165 ui::MouseEvent(mouse_released ? ET_MOUSE_RELEASED : ET_MOUSE_PRESSED, |
| 158 position, position, ui::EventTimeForNow(), flags, 0)); | 166 position, position, ui::EventTimeForNow(), flags, 0)); |
| 159 drag_operation_->DispatchPointerEvent(event, | 167 drag_operation_->DispatchPointerEvent(event, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 180 | 188 |
| 181 DragController* drag_operation() const { return drag_operation_.get(); } | 189 DragController* drag_operation() const { return drag_operation_.get(); } |
| 182 | 190 |
| 183 const base::Optional<uint32_t>& drag_completed_action() { | 191 const base::Optional<uint32_t>& drag_completed_action() { |
| 184 return drag_completed_action_; | 192 return drag_completed_action_; |
| 185 } | 193 } |
| 186 const base::Optional<bool>& drag_completed_value() { | 194 const base::Optional<bool>& drag_completed_value() { |
| 187 return drag_completed_value_; | 195 return drag_completed_value_; |
| 188 } | 196 } |
| 189 | 197 |
| 198 ui::mojom::Cursor cursor() { return cursor_; } |
| 199 |
| 190 private: | 200 private: |
| 191 // Overridden from testing::Test: | 201 // Overridden from testing::Test: |
| 192 void SetUp() override { | 202 void SetUp() override { |
| 193 testing::Test::SetUp(); | 203 testing::Test::SetUp(); |
| 194 | 204 |
| 195 window_delegate_ = base::MakeUnique<TestServerWindowDelegate>(); | 205 window_delegate_ = base::MakeUnique<TestServerWindowDelegate>(); |
| 196 root_window_ = | 206 root_window_ = |
| 197 base::MakeUnique<ServerWindow>(window_delegate_.get(), WindowId(1, 2)); | 207 base::MakeUnique<ServerWindow>(window_delegate_.get(), WindowId(1, 2)); |
| 198 window_delegate_->set_root_window(root_window_.get()); | 208 window_delegate_->set_root_window(root_window_.get()); |
| 199 root_window_->SetVisible(true); | 209 root_window_->SetVisible(true); |
| 200 } | 210 } |
| 201 | 211 |
| 202 void TearDown() override { | 212 void TearDown() override { |
| 203 drag_operation_.reset(); | 213 drag_operation_.reset(); |
| 204 root_window_.reset(); | 214 root_window_.reset(); |
| 205 window_delegate_.reset(); | 215 window_delegate_.reset(); |
| 206 | 216 |
| 207 DCHECK(server_window_by_id_.empty()); | 217 DCHECK(server_window_by_id_.empty()); |
| 208 DCHECK(connection_by_window_.empty()); | 218 DCHECK(connection_by_window_.empty()); |
| 209 | 219 |
| 210 testing::Test::TearDown(); | 220 testing::Test::TearDown(); |
| 211 } | 221 } |
| 212 | 222 |
| 223 // Overridden from DragCursorUpdater: |
| 224 void OnDragCursorUpdated() override { |
| 225 if (drag_operation_) |
| 226 cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor()); |
| 227 } |
| 228 |
| 213 // Overridden from DragControllerSource: | 229 // Overridden from DragControllerSource: |
| 214 void OnDragCompleted(bool success, uint32_t action_taken) override { | 230 void OnDragCompleted(bool success, uint32_t action_taken) override { |
| 215 drag_completed_action_ = action_taken; | 231 drag_completed_action_ = action_taken; |
| 216 drag_completed_value_ = success; | 232 drag_completed_value_ = success; |
| 217 } | 233 } |
| 218 | 234 |
| 219 ServerWindow* GetWindowById(const WindowId& id) override { | 235 ServerWindow* GetWindowById(const WindowId& id) override { |
| 220 auto it = server_window_by_id_.find(id); | 236 auto it = server_window_by_id_.find(id); |
| 221 if (it == server_window_by_id_.end()) | 237 if (it == server_window_by_id_.end()) |
| 222 return nullptr; | 238 return nullptr; |
| 223 return it->second; | 239 return it->second; |
| 224 } | 240 } |
| 225 | 241 |
| 226 DragTargetConnection* GetDragTargetForWindow( | 242 DragTargetConnection* GetDragTargetForWindow( |
| 227 const ServerWindow* window) override { | 243 const ServerWindow* window) override { |
| 228 auto it = connection_by_window_.find(const_cast<ServerWindow*>(window)); | 244 auto it = connection_by_window_.find(const_cast<ServerWindow*>(window)); |
| 229 if (it == connection_by_window_.end()) | 245 if (it == connection_by_window_.end()) |
| 230 return nullptr; | 246 return nullptr; |
| 231 return it->second; | 247 return it->second; |
| 232 } | 248 } |
| 233 | 249 |
| 234 int window_id_ = 3; | 250 int window_id_ = 3; |
| 235 | 251 |
| 252 ui::mojom::Cursor cursor_; |
| 253 |
| 236 std::map<WindowId, ServerWindow*> server_window_by_id_; | 254 std::map<WindowId, ServerWindow*> server_window_by_id_; |
| 237 std::map<ServerWindow*, DragTargetConnection*> connection_by_window_; | 255 std::map<ServerWindow*, DragTargetConnection*> connection_by_window_; |
| 238 | 256 |
| 239 std::unique_ptr<TestServerWindowDelegate> window_delegate_; | 257 std::unique_ptr<TestServerWindowDelegate> window_delegate_; |
| 240 std::unique_ptr<ServerWindow> root_window_; | 258 std::unique_ptr<ServerWindow> root_window_; |
| 241 | 259 |
| 242 std::unique_ptr<DragController> drag_operation_; | 260 std::unique_ptr<DragController> drag_operation_; |
| 243 | 261 |
| 244 base::Optional<uint32_t> drag_completed_action_; | 262 base::Optional<uint32_t> drag_completed_action_; |
| 245 base::Optional<bool> drag_completed_value_; | 263 base::Optional<bool> drag_completed_value_; |
| 246 }; | 264 }; |
| 247 | 265 |
| 248 DragTestWindow::~DragTestWindow() { | 266 DragTestWindow::~DragTestWindow() { |
| 249 parent_->OnTestWindowDestroyed(this); | 267 parent_->OnTestWindowDestroyed(this); |
| 250 } | 268 } |
| 251 | 269 |
| 252 TEST_F(DragControllerTest, SimpleDragDrop) { | 270 TEST_F(DragControllerTest, SimpleDragDrop) { |
| 253 std::unique_ptr<DragTestWindow> window = BuildWindow(); | 271 std::unique_ptr<DragTestWindow> window = BuildWindow(); |
| 254 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | 272 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; |
| 255 StartDragOperation(std::move(mime_data), window.get(), | 273 StartDragOperation(std::move(mime_data), window.get(), |
| 256 ui::mojom::kDropEffectMove); | 274 ui::mojom::kDropEffectMove); |
| 257 | 275 |
| 276 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 277 |
| 258 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | 278 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); |
| 259 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | 279 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); |
| 260 window->Respond(true); | 280 window->Respond(true); |
| 261 | 281 |
| 282 // (Even though we're doing a move, the cursor name is COPY.) |
| 283 EXPECT_EQ(ui::mojom::Cursor::COPY, cursor()); |
| 284 |
| 262 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | 285 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); |
| 263 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | 286 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); |
| 264 window->Respond(true); | 287 window->Respond(true); |
| 265 | 288 |
| 266 DispatchDrag(window.get(), true, 0, gfx::Point(2, 2)); | 289 DispatchDrag(window.get(), true, 0, gfx::Point(2, 2)); |
| 267 EXPECT_EQ(QueuedType::DROP, window->queue_response_type()); | 290 EXPECT_EQ(QueuedType::DROP, window->queue_response_type()); |
| 268 window->Respond(true); | 291 window->Respond(true); |
| 269 | 292 |
| 270 EXPECT_EQ(ui::mojom::kDropEffectMove, | 293 EXPECT_EQ(ui::mojom::kDropEffectMove, |
| 271 drag_completed_action().value_or(ui::mojom::kDropEffectNone)); | 294 drag_completed_action().value_or(ui::mojom::kDropEffectNone)); |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 window2.reset(); | 538 window2.reset(); |
| 516 | 539 |
| 517 // DragController doesn't know anything about the server window now. | 540 // DragController doesn't know anything about the server window now. |
| 518 EXPECT_EQ(0u, api.GetSizeOfQueueForWindow(server_window)); | 541 EXPECT_EQ(0u, api.GetSizeOfQueueForWindow(server_window)); |
| 519 EXPECT_EQ(nullptr, api.GetCurrentTarget()); | 542 EXPECT_EQ(nullptr, api.GetCurrentTarget()); |
| 520 | 543 |
| 521 // But a target window closing out from under us doesn't fail the drag. | 544 // But a target window closing out from under us doesn't fail the drag. |
| 522 EXPECT_FALSE(drag_completed_value().has_value()); | 545 EXPECT_FALSE(drag_completed_value().has_value()); |
| 523 } | 546 } |
| 524 | 547 |
| 548 TEST_F(DragControllerTest, TargetWindowClosedResetsCursor) { |
| 549 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); |
| 550 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); |
| 551 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; |
| 552 StartDragOperation(std::move(mime_data), window1.get(), |
| 553 ui::mojom::kDropEffectMove); |
| 554 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 555 |
| 556 // Send some events to |window|. |
| 557 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 558 gfx::Point(1, 1)); |
| 559 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); |
| 560 window2->Respond(true); |
| 561 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 562 gfx::Point(1, 1)); |
| 563 window2->Respond(true); |
| 564 EXPECT_EQ(ui::mojom::Cursor::COPY, cursor()); |
| 565 |
| 566 // Force the destruction of |window.window|. |
| 567 window2.reset(); |
| 568 |
| 569 // The cursor no loner indicates that it can drop on |window2|. |
| 570 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 571 } |
| 572 |
| 525 TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) { | 573 TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) { |
| 526 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | 574 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); |
| 527 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | 575 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); |
| 528 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | 576 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; |
| 529 StartDragOperation(std::move(mime_data), window1.get(), | 577 StartDragOperation(std::move(mime_data), window1.get(), |
| 530 ui::mojom::kDropEffectMove); | 578 ui::mojom::kDropEffectMove); |
| 531 | 579 |
| 532 test::DragControllerTestApi api(drag_operation()); | 580 test::DragControllerTestApi api(drag_operation()); |
| 533 | 581 |
| 534 // Send some events to |window|. | 582 // Send some events to |windoww|. |
| 535 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | 583 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 536 gfx::Point(1, 1)); | 584 gfx::Point(1, 1)); |
| 537 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); | 585 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); |
| 538 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | 586 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 539 gfx::Point(1, 1)); | 587 gfx::Point(1, 1)); |
| 540 | 588 |
| 541 ServerWindow* server_window = window2->window(); | 589 ServerWindow* server_window = window2->window(); |
| 542 | 590 |
| 543 // Ensure that DragController is waiting for a response from |window|. | 591 // Ensure that DragController is waiting for a response from |window2|. |
| 544 EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(server_window)); | 592 EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(server_window)); |
| 545 EXPECT_EQ(server_window, api.GetCurrentTarget()); | 593 EXPECT_EQ(server_window, api.GetCurrentTarget()); |
| 546 | 594 |
| 547 // Force the destruction of the source window. | 595 // Force the destruction of the source window. |
| 548 window1.reset(); | 596 window1.reset(); |
| 549 | 597 |
| 550 // The source window going away fails the drag. | 598 // The source window going away fails the drag. |
| 551 EXPECT_FALSE(drag_completed_value().value_or(true)); | 599 EXPECT_FALSE(drag_completed_value().value_or(true)); |
| 552 } | 600 } |
| 553 | 601 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 // This starts the operation with PointerEvent::kMousePointerId. | 650 // This starts the operation with PointerEvent::kMousePointerId. |
| 603 StartDragOperation(std::move(mime_data), window.get(), | 651 StartDragOperation(std::move(mime_data), window.get(), |
| 604 ui::mojom::kDropEffectMove); | 652 ui::mojom::kDropEffectMove); |
| 605 | 653 |
| 606 // Ignore events from pointer 5. | 654 // Ignore events from pointer 5. |
| 607 DispatchDragWithPointer(window.get(), 5, false, ui::EF_LEFT_MOUSE_BUTTON, | 655 DispatchDragWithPointer(window.get(), 5, false, ui::EF_LEFT_MOUSE_BUTTON, |
| 608 gfx::Point(1, 1)); | 656 gfx::Point(1, 1)); |
| 609 ASSERT_EQ(0u, window->queue_size()); | 657 ASSERT_EQ(0u, window->queue_size()); |
| 610 } | 658 } |
| 611 | 659 |
| 612 // TODO(erg): Add a test to ensure windows that the cursor isn't over | 660 TEST_F(DragControllerTest, RejectingWindowHasProperCursor) { |
| 613 // responding to messages don't change the cursor when we have cursor handling | 661 std::unique_ptr<DragTestWindow> window = BuildWindow(); |
| 614 // code. | 662 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; |
| 663 StartDragOperation(std::move(mime_data), window.get(), |
| 664 ui::mojom::kDropEffectMove); |
| 665 |
| 666 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 667 |
| 668 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); |
| 669 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); |
| 670 window->Respond(true); |
| 671 |
| 672 EXPECT_EQ(ui::mojom::Cursor::COPY, cursor()); |
| 673 |
| 674 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); |
| 675 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); |
| 676 |
| 677 // At this point, we respond with no available drag actions at this pixel. |
| 678 window->Respond(false); |
| 679 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 680 } |
| 681 |
| 682 TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) { |
| 683 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); |
| 684 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); |
| 685 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; |
| 686 StartDragOperation(std::move(mime_data), window1.get(), |
| 687 ui::mojom::kDropEffectMove); |
| 688 |
| 689 // Send some events to |window2|. |
| 690 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 691 gfx::Point(1, 1)); |
| 692 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); |
| 693 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 694 gfx::Point(1, 1)); |
| 695 |
| 696 EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor()); |
| 697 |
| 698 // Now enter |window1|, and respond. |
| 699 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, |
| 700 gfx::Point(5, 5)); |
| 701 EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type()); |
| 702 window1->Respond(true); |
| 703 |
| 704 EXPECT_EQ(ui::mojom::Cursor::COPY, cursor()); |
| 705 |
| 706 // Window 2 responding negatively to its queued messages shouldn't change the |
| 707 // cursor. |
| 708 window2->Respond(false); |
| 709 |
| 710 EXPECT_EQ(ui::mojom::Cursor::COPY, cursor()); |
| 711 } |
| 615 | 712 |
| 616 } // namespace ws | 713 } // namespace ws |
| 617 } // namespace ui | 714 } // namespace ui |
| OLD | NEW |