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