OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "services/ui/ws/drag_controller.h" | |
sky
2016/09/13 18:15:31
newline between 5/6.
| |
6 #include "services/ui/ws/drag_source.h" | |
7 #include "services/ui/ws/drag_target_connection.h" | |
8 #include "services/ui/ws/ids.h" | |
9 #include "services/ui/ws/server_window.h" | |
10 #include "services/ui/ws/test_server_window_delegate.h" | |
11 #include "services/ui/ws/test_utils.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include "ui/events/base_event_utils.h" | |
14 | |
15 namespace ui { | |
16 namespace ws { | |
17 | |
18 enum class QueuedType { NONE, ENTER, OVER, LEAVE, DROP }; | |
19 | |
20 class DragControllerTest; | |
21 | |
22 // All the classes to represent a window. | |
23 class DragTestWindow : public DragTargetConnection { | |
24 public: | |
25 struct DragEvent { | |
26 QueuedType type; | |
27 uint32_t key_state; | |
28 gfx::Point cursor_offset; | |
29 uint32_t effect_bitmask; | |
30 base::Callback<void(uint32_t)> callback; | |
31 }; | |
32 | |
33 DragTestWindow(DragControllerTest* parent, const WindowId& id) | |
34 : parent_(parent), window_delegate_(), window_(&window_delegate_, id) { | |
35 window_.SetCanAcceptDrops(true); | |
36 } | |
37 ~DragTestWindow() override; | |
38 | |
39 TestServerWindowDelegate* delegate() { return &window_delegate_; } | |
40 ServerWindow* window() { return &window_; } | |
41 | |
42 QueuedType queue_response_type() { | |
43 if (queued_callbacks_.empty()) | |
44 return QueuedType::NONE; | |
45 return queued_callbacks_.front().type; | |
46 } | |
47 | |
48 const DragEvent& queue_front() { return queued_callbacks_.front(); } | |
49 | |
50 size_t queue_size() { return queued_callbacks_.size(); } | |
51 | |
52 uint32_t times_received_drag_mime_types() { | |
53 return times_received_drag_mime_types_; | |
54 } | |
55 | |
56 void SetParent(DragTestWindow* p) { p->window_.Add(&window_); } | |
57 | |
58 void OptOutOfDrag() { window_.SetCanAcceptDrops(false); } | |
59 | |
60 // Calls the callback at the front of the queue. | |
61 void Respond(bool respond_with_effect) { | |
62 if (queued_callbacks_.size()) { | |
63 if (!queued_callbacks_.front().callback.is_null()) { | |
64 queued_callbacks_.front().callback.Run( | |
65 respond_with_effect ? queued_callbacks_.front().effect_bitmask : 0); | |
66 } | |
67 | |
68 queued_callbacks_.pop(); | |
69 } | |
70 } | |
71 | |
72 // Overridden from DragTestConnection: | |
73 void PerformOnDragMimeTypes( | |
74 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data) override { | |
75 times_received_drag_mime_types_++; | |
76 mime_data_ = std::move(mime_data); | |
77 } | |
78 | |
79 void PerformOnDragEnter( | |
80 const ServerWindow* window, | |
81 uint32_t key_state, | |
82 const gfx::Point& cursor_offset, | |
83 uint32_t effect_bitmask, | |
84 const base::Callback<void(uint32_t)>& callback) override { | |
85 DCHECK_EQ(window, &window_); | |
86 queued_callbacks_.push({QueuedType::ENTER, key_state, cursor_offset, | |
87 effect_bitmask, callback}); | |
88 } | |
89 | |
90 void PerformOnDragOver( | |
91 const ServerWindow* window, | |
92 uint32_t key_state, | |
93 const gfx::Point& cursor_offset, | |
94 uint32_t effect_bitmask, | |
95 const base::Callback<void(uint32_t)>& callback) override { | |
96 DCHECK_EQ(window, &window_); | |
97 queued_callbacks_.push( | |
98 {QueuedType::OVER, key_state, cursor_offset, effect_bitmask, callback}); | |
99 } | |
100 | |
101 void PerformOnDragLeave(const ServerWindow* window) override { | |
102 DCHECK_EQ(window, &window_); | |
103 queued_callbacks_.push({QueuedType::LEAVE, 0, gfx::Point(), 0, | |
104 base::Callback<void(uint32_t)>()}); | |
105 } | |
106 | |
107 void PerformOnCompleteDrop( | |
108 const ServerWindow* window, | |
109 uint32_t key_state, | |
110 const gfx::Point& cursor_offset, | |
111 uint32_t effect_bitmask, | |
112 const base::Callback<void(uint32_t)>& callback) override { | |
113 DCHECK_EQ(window, &window_); | |
114 queued_callbacks_.push( | |
115 {QueuedType::DROP, key_state, cursor_offset, effect_bitmask, callback}); | |
116 } | |
117 | |
118 void PerformOnDragFinish() override { mime_data_.SetToEmpty(); } | |
119 | |
120 private: | |
121 DragControllerTest* parent_; | |
122 TestServerWindowDelegate window_delegate_; | |
123 ServerWindow window_; | |
124 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data_; | |
125 uint32_t times_received_drag_mime_types_ = 0; | |
126 | |
127 std::queue<DragEvent> queued_callbacks_; | |
128 }; | |
129 | |
130 class DragControllerTest : public testing::Test, public DragSource { | |
131 public: | |
132 std::unique_ptr<DragTestWindow> BuildWindow() { | |
133 WindowId id(1, ++window_id_); | |
134 std::unique_ptr<DragTestWindow> p = | |
135 base::MakeUnique<DragTestWindow>(this, id); | |
136 server_window_by_id_[id] = p->window(); | |
137 connection_by_window_[p->window()] = p.get(); | |
138 return p; | |
139 } | |
140 | |
141 void StartDragOperation( | |
142 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data, | |
143 DragTestWindow* window, | |
144 uint32_t drag_operations) { | |
145 window->PerformOnDragMimeTypes(mime_data.Clone()); | |
146 drag_operation_.reset(new DragController( | |
147 this, window->window(), window, PointerEvent::kMousePointerId, | |
148 std::move(mime_data), drag_operations)); | |
149 } | |
150 | |
151 void DispatchDrag(DragTestWindow* window, | |
152 bool mouse_released, | |
153 uint32_t flags, | |
154 const gfx::Point& position) { | |
155 ui::PointerEvent event( | |
156 ui::MouseEvent(mouse_released ? ET_MOUSE_RELEASED : ET_MOUSE_PRESSED, | |
157 position, position, ui::EventTimeForNow(), flags, 0)); | |
158 drag_operation_->DispatchPointerEvent(event, | |
159 window ? window->window() : nullptr); | |
160 } | |
161 | |
162 void DispatchDragWithPointer(DragTestWindow* window, | |
163 int32_t drag_pointer, | |
164 bool mouse_released, | |
165 uint32_t flags, | |
166 const gfx::Point& position) { | |
167 ui::PointerEvent event(ET_POINTER_DOWN, position, position, flags, | |
168 drag_pointer, 0, PointerDetails(), | |
169 base::TimeTicks()); | |
170 drag_operation_->DispatchPointerEvent(event, | |
171 window ? window->window() : nullptr); | |
172 } | |
173 | |
174 void OnTestWindowDestroyed(DragTestWindow* test_window) { | |
175 drag_operation_->OnWillDestroyDragTargetConnection(test_window); | |
176 server_window_by_id_.erase(test_window->window()->id()); | |
177 connection_by_window_.erase(test_window->window()); | |
178 } | |
179 | |
180 DragController* drag_operation() const { return drag_operation_.get(); } | |
181 const base::Optional<bool>& drag_completed_value() { | |
182 return drag_completed_value_; | |
183 } | |
184 | |
185 private: | |
186 // Overridden from testing::Test: | |
187 void SetUp() override { | |
188 testing::Test::SetUp(); | |
189 | |
190 window_delegate_.reset(new TestServerWindowDelegate()); | |
191 root_window_.reset( | |
192 new ServerWindow(window_delegate_.get(), WindowId(1, 2))); | |
193 window_delegate_->set_root_window(root_window_.get()); | |
194 root_window_->SetVisible(true); | |
195 } | |
196 | |
197 void TearDown() override { | |
198 drag_operation_.reset(); | |
199 root_window_.reset(); | |
200 window_delegate_.reset(); | |
201 | |
202 DCHECK(server_window_by_id_.empty()); | |
203 DCHECK(connection_by_window_.empty()); | |
204 | |
205 testing::Test::TearDown(); | |
206 } | |
207 | |
208 // Overridden from DragControllerSource: | |
209 void OnDragCompleted(bool success) override { | |
210 drag_completed_value_ = success; | |
211 } | |
212 | |
213 ServerWindow* GetWindowById(const WindowId& id) override { | |
214 auto it = server_window_by_id_.find(id); | |
215 if (it == server_window_by_id_.end()) | |
216 return nullptr; | |
217 return it->second; | |
218 } | |
219 | |
220 DragTargetConnection* GetDragTargetWithRoot( | |
221 const ServerWindow* window) override { | |
222 auto it = connection_by_window_.find(const_cast<ServerWindow*>(window)); | |
223 if (it == connection_by_window_.end()) | |
224 return nullptr; | |
225 return it->second; | |
226 } | |
227 | |
228 int window_id_ = 3; | |
229 | |
230 std::map<WindowId, ServerWindow*> server_window_by_id_; | |
231 std::map<ServerWindow*, DragTargetConnection*> connection_by_window_; | |
232 | |
233 std::unique_ptr<TestServerWindowDelegate> window_delegate_; | |
234 std::unique_ptr<ServerWindow> root_window_; | |
235 | |
236 std::unique_ptr<DragController> drag_operation_; | |
237 | |
238 base::Optional<bool> drag_completed_value_; | |
239 }; | |
240 | |
241 DragTestWindow::~DragTestWindow() { | |
242 parent_->OnTestWindowDestroyed(this); | |
243 } | |
244 | |
245 TEST_F(DragControllerTest, SimpleDragDrop) { | |
246 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
247 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
248 StartDragOperation(std::move(mime_data), window.get(), | |
249 ui::mojom::kDropEffectMove); | |
250 | |
251 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
252 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
253 window->Respond(true); | |
254 | |
255 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
256 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | |
257 window->Respond(true); | |
258 | |
259 DispatchDrag(window.get(), true, 0, gfx::Point(2, 2)); | |
260 EXPECT_EQ(QueuedType::DROP, window->queue_response_type()); | |
261 window->Respond(true); | |
262 | |
263 EXPECT_TRUE(drag_completed_value().value_or(false)); | |
264 } | |
265 | |
266 TEST_F(DragControllerTest, OnlyDeliverMimeDataOnce) { | |
267 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
268 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
269 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
270 | |
271 // The client lib is responsible for sending the data to the window that's | |
272 // the drag source to minimize IPC. | |
273 EXPECT_EQ(0u, window1->times_received_drag_mime_types()); | |
274 StartDragOperation(std::move(mime_data), window1.get(), | |
275 ui::mojom::kDropEffectMove); | |
276 EXPECT_EQ(1u, window1->times_received_drag_mime_types()); | |
277 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
278 gfx::Point(1, 1)); | |
279 EXPECT_EQ(1u, window1->times_received_drag_mime_types()); | |
280 window1->Respond(true); | |
281 | |
282 // Window2 doesn't receive the drag data until mouse is over it. | |
283 EXPECT_EQ(0u, window2->times_received_drag_mime_types()); | |
284 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
285 gfx::Point(2, 2)); | |
286 EXPECT_EQ(1u, window2->times_received_drag_mime_types()); | |
287 | |
288 // Moving back to the source window doesn't send an additional start message. | |
289 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
290 gfx::Point(1, 1)); | |
291 EXPECT_EQ(1u, window1->times_received_drag_mime_types()); | |
292 | |
293 // Moving back to window2 doesn't send an additional start message. | |
294 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
295 gfx::Point(1, 1)); | |
296 EXPECT_EQ(1u, window2->times_received_drag_mime_types()); | |
297 } | |
298 | |
299 TEST_F(DragControllerTest, DeliverMessageToParent) { | |
300 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
301 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
302 std::unique_ptr<DragTestWindow> window3 = BuildWindow(); | |
303 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
304 | |
305 window3->SetParent(window2.get()); | |
306 window3->OptOutOfDrag(); | |
307 | |
308 StartDragOperation(std::move(mime_data), window1.get(), | |
309 ui::mojom::kDropEffectMove); | |
310 | |
311 // Dispatching a drag to window3 (which has can accept drags off) redirects | |
312 // to window2, which is its parent. | |
313 DispatchDrag(window3.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
314 gfx::Point(1, 1)); | |
315 EXPECT_EQ(1u, window2->times_received_drag_mime_types()); | |
316 } | |
317 | |
318 TEST_F(DragControllerTest, FailWhenDropOverNoWindow) { | |
319 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
320 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
321 StartDragOperation(std::move(mime_data), window.get(), | |
322 ui::mojom::kDropEffectMove); | |
323 | |
324 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
325 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
326 window->Respond(true); | |
327 | |
328 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
329 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | |
330 window->Respond(true); | |
331 | |
332 DispatchDrag(nullptr, true, 0, gfx::Point(2, 2)); | |
333 // Moving outside of |window| should result in |window| getting a leave. | |
334 EXPECT_EQ(QueuedType::LEAVE, window->queue_response_type()); | |
335 window->Respond(true); | |
336 | |
337 EXPECT_FALSE(drag_completed_value().value_or(true)); | |
338 } | |
339 | |
340 TEST_F(DragControllerTest, EnterLeaveWhenMovingBetweenTwoWindows) { | |
341 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
342 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
343 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
344 StartDragOperation(std::move(mime_data), window1.get(), | |
345 ui::mojom::kDropEffectMove); | |
346 | |
347 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
348 gfx::Point(1, 1)); | |
349 EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type()); | |
350 window1->Respond(true); | |
351 | |
352 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
353 gfx::Point(2, 2)); | |
354 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); | |
355 EXPECT_EQ(QueuedType::LEAVE, window1->queue_response_type()); | |
356 window1->Respond(true); | |
357 window2->Respond(true); | |
358 } | |
359 | |
360 TEST_F(DragControllerTest, DeadWindowDoesntBlock) { | |
361 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
362 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
363 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
364 StartDragOperation(std::move(mime_data), window1.get(), | |
365 ui::mojom::kDropEffectMove); | |
366 | |
367 test::DragControllerTestApi api(drag_operation()); | |
368 | |
369 // Simulate a dead window by giving it a few messages, but don't respond to | |
370 // them. | |
371 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
372 gfx::Point(1, 1)); | |
373 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
374 gfx::Point(2, 2)); | |
375 EXPECT_EQ(1u, window1->queue_size()); | |
376 EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(window1->window())); | |
377 | |
378 // Moving to window2 should dispatch the enter event to it immediately. | |
379 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
380 gfx::Point(3, 3)); | |
381 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); | |
382 EXPECT_EQ(1u, window1->queue_size()); | |
383 } | |
384 | |
385 TEST_F(DragControllerTest, EnterToOverQueued) { | |
386 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
387 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
388 StartDragOperation(std::move(mime_data), window.get(), | |
389 ui::mojom::kDropEffectMove); | |
390 | |
391 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
392 ASSERT_EQ(1u, window->queue_size()); | |
393 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
394 // Don't respond. | |
395 | |
396 // We don't receive another message since we haven't acknowledged the first. | |
397 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 2)); | |
398 ASSERT_EQ(1u, window->queue_size()); | |
399 | |
400 // Responding causes us to receive our next event. | |
401 window->Respond(true); | |
402 ASSERT_EQ(1u, window->queue_size()); | |
403 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | |
404 } | |
405 | |
406 TEST_F(DragControllerTest, CoalesceMouseOverEvents) { | |
407 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
408 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
409 StartDragOperation(std::move(mime_data), window.get(), | |
410 ui::mojom::kDropEffectMove); | |
411 | |
412 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
413 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
414 | |
415 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 2)); | |
416 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
417 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 3)); | |
418 | |
419 // Responding to the first delivers us the last mouse over event's position. | |
420 window->Respond(true); | |
421 ASSERT_EQ(1u, window->queue_size()); | |
422 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | |
423 EXPECT_EQ(gfx::Point(2, 3), window->queue_front().cursor_offset); | |
424 | |
425 // There are no queued events because they were coalesced. | |
426 window->Respond(true); | |
427 EXPECT_EQ(0u, window->queue_size()); | |
428 } | |
429 | |
430 TEST_F(DragControllerTest, RemovePendingMouseOversOnLeave) { | |
431 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
432 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
433 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
434 StartDragOperation(std::move(mime_data), window1.get(), | |
435 ui::mojom::kDropEffectMove); | |
436 | |
437 // Enter | |
438 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
439 gfx::Point(1, 1)); | |
440 EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type()); | |
441 | |
442 // Over | |
443 DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
444 gfx::Point(1, 1)); | |
445 | |
446 // Leave | |
447 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
448 gfx::Point(1, 1)); | |
449 | |
450 // The window finally responds to the enter message; we should not receive | |
451 // any over messages since we didn't respond to the enter message in time. | |
452 window1->Respond(true); | |
453 ASSERT_EQ(1u, window1->queue_size()); | |
454 EXPECT_EQ(QueuedType::LEAVE, window1->queue_response_type()); | |
455 } | |
456 | |
457 TEST_F(DragControllerTest, TargetWindowClosedWhileDrag) { | |
458 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
459 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
460 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
461 StartDragOperation(std::move(mime_data), window1.get(), | |
462 ui::mojom::kDropEffectMove); | |
463 | |
464 test::DragControllerTestApi api(drag_operation()); | |
465 | |
466 // Send some events to |window|. | |
467 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
468 gfx::Point(1, 1)); | |
469 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); | |
470 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
471 gfx::Point(1, 1)); | |
472 | |
473 ServerWindow* server_window = window2->window(); | |
474 | |
475 // Ensure that DragController is waiting for a response from |window|. | |
476 EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(server_window)); | |
477 EXPECT_EQ(server_window, api.GetCurrentTarget()); | |
478 | |
479 // Force the destruction of |window.window|. | |
480 window2.reset(); | |
481 | |
482 // DragController doesn't know anything about the server window now. | |
483 EXPECT_EQ(0u, api.GetSizeOfQueueForWindow(server_window)); | |
484 EXPECT_EQ(nullptr, api.GetCurrentTarget()); | |
485 | |
486 // But a target window closing out from under us doesn't fail the drag. | |
487 EXPECT_FALSE(drag_completed_value().has_value()); | |
488 } | |
489 | |
490 TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) { | |
491 std::unique_ptr<DragTestWindow> window1 = BuildWindow(); | |
492 std::unique_ptr<DragTestWindow> window2 = BuildWindow(); | |
493 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
494 StartDragOperation(std::move(mime_data), window1.get(), | |
495 ui::mojom::kDropEffectMove); | |
496 | |
497 test::DragControllerTestApi api(drag_operation()); | |
498 | |
499 // Send some events to |window|. | |
500 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
501 gfx::Point(1, 1)); | |
502 EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type()); | |
503 DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, | |
504 gfx::Point(1, 1)); | |
505 | |
506 ServerWindow* server_window = window2->window(); | |
507 | |
508 // Ensure that DragController is waiting for a response from |window|. | |
509 EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(server_window)); | |
510 EXPECT_EQ(server_window, api.GetCurrentTarget()); | |
511 | |
512 // Force the destruction of the source window. | |
513 window1.reset(); | |
514 | |
515 // The source window going away fails the drag. | |
516 EXPECT_FALSE(drag_completed_value().value_or(true)); | |
517 } | |
518 | |
519 TEST_F(DragControllerTest, DontQueueEventsAfterDrop) { | |
520 // The DragController needs to stick around to coordinate the drop, but | |
521 // it should ignore further mouse events during this time. | |
522 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
523 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
524 StartDragOperation(std::move(mime_data), window.get(), | |
525 ui::mojom::kDropEffectMove); | |
526 | |
527 test::DragControllerTestApi api(drag_operation()); | |
528 | |
529 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
530 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
531 window->Respond(true); | |
532 | |
533 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
534 EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); | |
535 window->Respond(true); | |
536 | |
537 DispatchDrag(window.get(), true, 0, gfx::Point(2, 2)); | |
538 EXPECT_EQ(QueuedType::DROP, window->queue_response_type()); | |
539 EXPECT_EQ(1u, api.GetSizeOfQueueForWindow(window->window())); | |
540 | |
541 // Further located events don't result in additional drag messages. | |
542 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
543 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); | |
544 EXPECT_EQ(1u, api.GetSizeOfQueueForWindow(window->window())); | |
545 } | |
546 | |
547 TEST_F(DragControllerTest, CancelDrag) { | |
548 // The DragController needs to stick around to coordinate the drop, but | |
549 // it should ignore further mouse events during this time. | |
550 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
551 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
552 StartDragOperation(std::move(mime_data), window.get(), | |
553 ui::mojom::kDropEffectMove); | |
554 | |
555 DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); | |
556 EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); | |
557 window->Respond(true); | |
558 | |
559 drag_operation()->Cancel(); | |
560 | |
561 EXPECT_FALSE(drag_completed_value().value_or(true)); | |
562 } | |
563 | |
564 TEST_F(DragControllerTest, IgnoreEventsFromOtherPointers) { | |
565 std::unique_ptr<DragTestWindow> window = BuildWindow(); | |
566 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data; | |
567 // This starts the operation with PointerEvent::kMousePointerId. | |
568 StartDragOperation(std::move(mime_data), window.get(), | |
569 ui::mojom::kDropEffectMove); | |
570 | |
571 // Ignore events from pointer 5. | |
572 DispatchDragWithPointer(window.get(), 5, false, ui::EF_LEFT_MOUSE_BUTTON, | |
573 gfx::Point(1, 1)); | |
574 ASSERT_EQ(0u, window->queue_size()); | |
575 } | |
576 | |
577 // TODO(erg): Add a test to ensure windows that the cursor isn't over | |
578 // responding to messages don't change the cursor when we have cursor handling | |
579 // code. | |
580 | |
581 } // namespace ws | |
582 } // namespace ui | |
OLD | NEW |