Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc

Issue 268083002: Add tests for drag and drop for Linux Aura (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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 <map>
6 #include <vector>
7 #include <X11/Xlib.h>
8
9 // Include views_test_base.h first because the definition of None in X.h
10 // conflicts with the definition of None in gtest-type-util.h
11 #include "ui/views/test/views_test_base.h"
12
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/base/dragdrop/os_exchange_data.h"
18 #include "ui/base/x/x11_util.h"
19 #include "ui/gfx/x/x11_atom_cache.h"
20 #include "ui/gfx/x/x11_types.h"
21 #include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
22 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
23 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
24 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
25 #include "ui/views/widget/widget.h"
26
27 namespace views {
28
29 namespace {
30
31 const char* kAtomsToCache[] = {
32 "XdndActionCopy",
33 "XdndDrop",
34 "XdndEnter",
35 "XdndFinished",
36 "XdndLeave",
37 "XdndPosition",
38 "XdndStatus",
39 "XdndTypeList",
40 NULL
41 };
42
43 class TestDragDropClient;
44
45 // Collects messages which would otherwise be sent to |xid_| via
46 // SendXClientEvent().
47 class ClientMessageEventCollector {
48 public:
49 ClientMessageEventCollector(::Window xid, TestDragDropClient* client);
50 virtual ~ClientMessageEventCollector();
51
52 // Returns true if |events_| is non-empty.
53 bool HasEvents() const {
54 return !events_.empty();
55 }
56
57 // Pops all of |events_| and returns the popped events in the order that they
58 // were on the stack
59 std::vector<XClientMessageEvent> PopAllEvents();
60
61 // Adds |event| to the stack.
62 void RecordEvent(const XClientMessageEvent& event);
63
64 private:
65 ::Window xid_;
66
67 // Not owned.
68 TestDragDropClient* client_;
69
70 std::vector<XClientMessageEvent> events_;
71
72 DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector);
73 };
74
75 // Implementation of DesktopDragDropClientAuraX11 which works with a fake
76 // |DesktopDragDropClientAuraX11::source_current_window_|.
77 class TestDragDropClient : public DesktopDragDropClientAuraX11 {
78 public:
79 // The location in screen coordinates used for the synthetic mouse moves
80 // generated in SetTopmostXWindowAndMoveMouse().
81 static const int kMouseMoveX;
82 static const int kMouseMoveY;
83
84 TestDragDropClient(aura::Window* window,
85 DesktopNativeCursorManager* cursor_manager);
86 virtual ~TestDragDropClient();
87
88 // Returns the XID of the window which initiated the drag.
89 ::Window source_xwindow() {
90 return source_xid_;
91 }
92
93 // Returns the Atom with |name|.
94 Atom GetAtom(const char* name);
95
96 // Returns true if the event's message has |type|.
97 bool MessageHasType(const XClientMessageEvent& event,
98 const char* type);
99
100 // Sets |collector| to collect XClientMessageEvents which would otherwise
101 // have been sent to the drop target window.
102 void SetEventCollectorFor(::Window xid,
103 ClientMessageEventCollector* collector);
104
105 // Builds an XdndStatus message and sends it to
106 // DesktopDragDropClientAuraX11.
107 void OnStatus(XID target_window,
108 bool will_accept_drop,
109 ::Atom accepted_action);
110
111 // Builds an XdndFinished message and sends it to
112 // DesktopDragDropClientAuraX11.
113 void OnFinished(XID target_window,
114 bool accepted_drop,
115 ::Atom performed_action);
116
117 // Sets |xid| as the topmost window at the current mouse position and
118 // generates a synthetic mouse move.
119 void SetTopmostXWindowAndMoveMouse(::Window xid);
120
121 // Returns true if the move loop is running.
122 bool IsMoveLoopRunning();
123
124 // DesktopDragDropClientAuraX11:
125 virtual int StartDragAndDrop(
126 const ui::OSExchangeData& data,
127 aura::Window* root_window,
128 aura::Window* source_window,
129 const gfx::Point& root_location,
130 int operation,
131 ui::DragDropTypes::DragEventSource source) OVERRIDE;
132 virtual void OnMoveLoopEnded() OVERRIDE;
133
134 private:
135 // DesktopDragDropClientAuraX11:
136 virtual ::Window FindWindowFor(const gfx::Point& screen_point) OVERRIDE;
137 virtual void SendXClientEvent(::Window xid, XEvent* event) OVERRIDE;
138
139 // The XID of the window which initiated the drag.
140 ::Window source_xid_;
141
142 // The XID of the window which is simulated to be the topmost window at the
143 // current mouse position.
144 ::Window target_xid_;
145
146 // Whether the move loop is running.
147 bool move_loop_running_;
148
149 // Map of ::Windows to the collector which intercepts XClientMessageEvents
150 // for that window.
151 std::map<::Window, ClientMessageEventCollector*> collectors_;
152
153 ui::X11AtomCache atom_cache_;
154
155 DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
156 };
157
158 ///////////////////////////////////////////////////////////////////////////////
159 // ClientMessageEventCollector
160
161 ClientMessageEventCollector::ClientMessageEventCollector(
162 ::Window xid,
163 TestDragDropClient* client)
164 : xid_(xid),
165 client_(client) {
166 client->SetEventCollectorFor(xid, this);
167 }
168
169 ClientMessageEventCollector::~ClientMessageEventCollector() {
170 client_->SetEventCollectorFor(xid_, NULL);
171 }
172
173 std::vector<XClientMessageEvent> ClientMessageEventCollector::PopAllEvents() {
174 std::vector<XClientMessageEvent> to_return;
175 to_return.swap(events_);
176 return to_return;
177 }
178
179 void ClientMessageEventCollector::RecordEvent(
180 const XClientMessageEvent& event) {
181 events_.push_back(event);
182 }
183
184 ///////////////////////////////////////////////////////////////////////////////
185 // TestDragDropClient
186
187 // static
188 const int TestDragDropClient::kMouseMoveX = 100;
189
190 // static
191 const int TestDragDropClient::kMouseMoveY = 200;
192
193 TestDragDropClient::TestDragDropClient(
194 aura::Window* window,
195 DesktopNativeCursorManager* cursor_manager)
196 : DesktopDragDropClientAuraX11(window,
197 cursor_manager,
198 gfx::GetXDisplay(),
199 window->GetHost()->GetAcceleratedWidget()),
200 source_xid_(window->GetHost()->GetAcceleratedWidget()),
201 target_xid_(None),
202 move_loop_running_(false),
203 atom_cache_(gfx::GetXDisplay(), kAtomsToCache) {
204 }
205
206 TestDragDropClient::~TestDragDropClient() {
207 }
208
209 Atom TestDragDropClient::GetAtom(const char* name) {
210 return atom_cache_.GetAtom(name);
211 }
212
213 bool TestDragDropClient::MessageHasType(const XClientMessageEvent& event,
214 const char* type) {
215 return event.message_type == atom_cache_.GetAtom(type);
216 }
217
218 void TestDragDropClient::SetEventCollectorFor(
219 ::Window xid,
220 ClientMessageEventCollector* collector) {
221 if (collector)
222 collectors_[xid] = collector;
223 else
224 collectors_.erase(xid);
225 }
226
227 void TestDragDropClient::OnStatus(XID target_window,
228 bool will_accept_drop,
229 ::Atom accepted_action) {
230 XClientMessageEvent event;
231 event.message_type = atom_cache_.GetAtom("XdndStatus");
232 event.format = 32;
233 event.window = source_xid_;
234 event.data.l[0] = target_window;
235 event.data.l[1] = will_accept_drop ? 1 : 0;
236 event.data.l[2] = 0;
237 event.data.l[3] = 0;
238 event.data.l[4] = accepted_action;
239 OnXdndStatus(event);
240 }
241
242 void TestDragDropClient::OnFinished(XID target_window,
243 bool accepted_drop,
244 ::Atom performed_action) {
245 XClientMessageEvent event;
246 event.message_type = atom_cache_.GetAtom("XdndFinished");
247 event.format = 32;
248 event.window = source_xid_;
249 event.data.l[0] = target_window;
250 event.data.l[1] = accepted_drop ? 1 : 0;
251 event.data.l[2] = performed_action;
252 event.data.l[3] = 0;
253 event.data.l[4] = 0;
254 OnXdndFinished(event);
255 }
256
257 void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
258 target_xid_ = xid;
259
260 XMotionEvent event;
261 event.time = CurrentTime;
262 event.x_root = kMouseMoveX;
263 event.y_root = kMouseMoveY;
264 OnMouseMovement(&event);
265 }
266
267 bool TestDragDropClient::IsMoveLoopRunning() {
268 return move_loop_running_;
269 }
270
271 int TestDragDropClient::StartDragAndDrop(
272 const ui::OSExchangeData& data,
273 aura::Window* root_window,
274 aura::Window* source_window,
275 const gfx::Point& root_location,
276 int operation,
277 ui::DragDropTypes::DragEventSource source) {
278 move_loop_running_ = true;
279 return DesktopDragDropClientAuraX11::StartDragAndDrop(data, root_window,
280 source_window, root_location, operation, source);
281 }
282
283 void TestDragDropClient::OnMoveLoopEnded() {
284 DesktopDragDropClientAuraX11::OnMoveLoopEnded();
285 move_loop_running_ = false;
286 }
287
288 ::Window TestDragDropClient::FindWindowFor(const gfx::Point& screen_point) {
289 return target_xid_;
290 }
291
292 void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
293 std::map<::Window, ClientMessageEventCollector*>::iterator it =
294 collectors_.find(xid);
295 if (it != collectors_.end())
296 it->second->RecordEvent(event->xclient);
297 }
298
299 } // namespace
300
301 class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
302 public:
303 DesktopDragDropClientAuraX11Test() {
304 }
305
306 virtual ~DesktopDragDropClientAuraX11Test() {
307 }
308
309 int StartDragAndDrop() {
310 ui::OSExchangeData data;
311 data.SetString(base::ASCIIToUTF16("Test"));
312
313 return client_->StartDragAndDrop(
314 data,
315 widget_->GetNativeWindow()->GetRootWindow(),
316 widget_->GetNativeWindow(),
317 gfx::Point(),
318 ui::DragDropTypes::DRAG_COPY,
319 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
320 }
321
322 // ViewsTestBase:
323 virtual void SetUp() OVERRIDE {
324 ViewsTestBase::SetUp();
325
326 // Create widget to initiate the drags.
327 widget_.reset(new Widget);
328 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
329 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
330 params.native_widget = new DesktopNativeWidgetAura(widget_.get());
331 params.bounds = gfx::Rect(100, 100);
332 widget_->Init(params);
333 widget_->Show();
334
335 cursor_manager_.reset(new DesktopNativeCursorManager(
336 DesktopCursorLoaderUpdater::Create()));
337
338 client_.reset(new TestDragDropClient(widget_->GetNativeWindow(),
339 cursor_manager_.get()));
340 }
341
342 virtual void TearDown() OVERRIDE {
343 client_.reset();
344 cursor_manager_.reset();
345 widget_.reset();
346 ViewsTestBase::TearDown();
347 }
348
349 TestDragDropClient* client() {
350 return client_.get();
351 }
352
353 private:
354 scoped_ptr<TestDragDropClient> client_;
355 scoped_ptr<DesktopNativeCursorManager> cursor_manager_;
356
357 // The widget used to initiate drags.
358 scoped_ptr<Widget> widget_;
359
360 DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test);
361 };
362
363 namespace {
364
365 void BasicStep2(TestDragDropClient* client, XID toplevel) {
366 EXPECT_TRUE(client->IsMoveLoopRunning());
367
368 ClientMessageEventCollector collector(toplevel, client);
369 client->SetTopmostXWindowAndMoveMouse(toplevel);
370
371 // XdndEnter should have been sent to |toplevel| before the XdndPosition
372 // message.
373 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
374 ASSERT_EQ(2u, events.size());
375
376 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
377 EXPECT_EQ(client->source_xwindow(),
378 static_cast<XID>(events[0].data.l[0]));
379 EXPECT_EQ(1, events[0].data.l[1] & 1);
380 std::vector<Atom> targets;
381 ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
382 EXPECT_FALSE(targets.empty());
383
384 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
385 EXPECT_EQ(client->source_xwindow(),
386 static_cast<XID>(events[0].data.l[0]));
387 const long kCoords =
388 TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY;
389 EXPECT_EQ(kCoords, events[1].data.l[2]);
390 EXPECT_EQ(client->GetAtom("XdndActionCopy"),
391 static_cast<Atom>(events[1].data.l[4]));
392
393 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
394
395 // Because there is no unprocessed XdndPosition, the drag drop client should
396 // send XdndDrop immediately after the mouse is released.
397 client->OnMouseReleased();
398
399 events = collector.PopAllEvents();
400 ASSERT_EQ(1u, events.size());
401 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
402 EXPECT_EQ(client->source_xwindow(),
403 static_cast<XID>(events[0].data.l[0]));
404
405 // Send XdndFinished to indicate that the drag drop client can cleanup any
406 // data related to this drag. The move loop should end only after the
407 // XdndFinished message was received.
408 EXPECT_TRUE(client->IsMoveLoopRunning());
409 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
410 EXPECT_FALSE(client->IsMoveLoopRunning());
411 }
412
413 void BasicStep3(TestDragDropClient* client, XID toplevel) {
414 EXPECT_TRUE(client->IsMoveLoopRunning());
415
416 ClientMessageEventCollector collector(toplevel, client);
417 client->SetTopmostXWindowAndMoveMouse(toplevel);
418
419 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
420 ASSERT_EQ(2u, events.size());
421 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
422 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
423
424 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
425 client->SetTopmostXWindowAndMoveMouse(toplevel);
426 events = collector.PopAllEvents();
427 ASSERT_EQ(1u, events.size());
428 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
429
430 // We have not received an XdndStatus ack for the second XdndPosition message.
431 // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
432 client->OnMouseReleased();
433 EXPECT_FALSE(collector.HasEvents());
434
435 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
436 events = collector.PopAllEvents();
437 ASSERT_EQ(1u, events.size());
438 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
439
440 EXPECT_TRUE(client->IsMoveLoopRunning());
441 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
442 EXPECT_FALSE(client->IsMoveLoopRunning());
443 }
444
445 } // namespace
446
447 TEST_F(DesktopDragDropClientAuraX11Test, Basic) {
448 XID toplevel = 1;
449
450 base::MessageLoop::current()->PostTask(FROM_HERE,
451 base::Bind(&BasicStep2,
452 client(),
453 toplevel));
454 int result = StartDragAndDrop();
455 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
456
457 // Do another drag and drop to test that the data is properly cleaned up as a
458 // result of the XdndFinished message.
459 base::MessageLoop::current()->PostTask(FROM_HERE,
460 base::Bind(&BasicStep3,
461 client(),
462 toplevel));
463 result = StartDragAndDrop();
464 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
465 }
466
467 namespace {
468
469 void TargetDoesNotRespondStep2(TestDragDropClient* client) {
470 EXPECT_TRUE(client->IsMoveLoopRunning());
471
472 XID toplevel = 1;
473 ClientMessageEventCollector collector(toplevel, client);
474 client->SetTopmostXWindowAndMoveMouse(toplevel);
475
476 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
477 ASSERT_EQ(2u, events.size());
478 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
479 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
480
481 client->OnMouseReleased();
482 events = collector.PopAllEvents();
483 ASSERT_EQ(1u, events.size());
484 EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
485 EXPECT_FALSE(client->IsMoveLoopRunning());
486 }
487
488 } // namespace
489
490 // Test that we do not wait for the target to send XdndStatus if we have not
491 // received any XdndStatus messages at all from the target. The Unity
492 // DNDCollectionWindow is an example of an XdndAware target which does not
493 // respond to XdndPosition messages at all.
494 TEST_F(DesktopDragDropClientAuraX11Test, TargetDoesNotRespond) {
495 base::MessageLoop::current()->PostTask(
496 FROM_HERE,
497 base::Bind(&TargetDoesNotRespondStep2, client()));
498 int result = StartDragAndDrop();
499 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
500 }
501
502 namespace {
503
504 void QueuePositionStep2(TestDragDropClient* client) {
505 EXPECT_TRUE(client->IsMoveLoopRunning());
506
507 XID toplevel = 1;
508 ClientMessageEventCollector collector(toplevel, client);
509 client->SetTopmostXWindowAndMoveMouse(toplevel);
510 client->SetTopmostXWindowAndMoveMouse(toplevel);
511 client->SetTopmostXWindowAndMoveMouse(toplevel);
512
513 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
514 ASSERT_EQ(2u, events.size());
515 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
516 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
517
518 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
519 events = collector.PopAllEvents();
520 ASSERT_EQ(1u, events.size());
521 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
522
523 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
524 EXPECT_FALSE(collector.HasEvents());
525
526 client->OnMouseReleased();
527 events = collector.PopAllEvents();
528 ASSERT_EQ(1u, events.size());
529 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDropped"));
530
531 EXPECT_TRUE(client->IsMoveLoopRunning());
532 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
533 EXPECT_FALSE(client->IsMoveLoopRunning());
534 }
535
536 } // namespace
537
538 // Test that XdndPosition messages are queued till the pending XdndPosition
539 // message is acked via an XdndStatus message.
540 TEST_F(DesktopDragDropClientAuraX11Test, QueuePosition) {
541 base::MessageLoop::current()->PostTask(
542 FROM_HERE,
543 base::Bind(&QueuePositionStep2, client()));
544 int result = StartDragAndDrop();
545 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
546 }
547
548 namespace {
549
550 void TargetChangesStep2(TestDragDropClient* client) {
551 EXPECT_TRUE(client->IsMoveLoopRunning());
552
553 XID toplevel1 = 1;
554 ClientMessageEventCollector collector1(toplevel1, client);
555 client->SetTopmostXWindowAndMoveMouse(toplevel1);
556
557 std::vector<XClientMessageEvent> events1 = collector1.PopAllEvents();
558 ASSERT_EQ(2u, events1.size());
559 EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter"));
560 EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition"));
561
562 XID toplevel2 = 2;
563 ClientMessageEventCollector collector2(toplevel2, client);
564 client->SetTopmostXWindowAndMoveMouse(toplevel2);
565
566 // It is possible for |toplevel1| to send XdndStatus after the source has sent
567 // XdndLeave but before |toplevel1| has received the XdndLeave message. The
568 // XdndStatus message should be ignored.
569 client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy"));
570 events1 = collector1.PopAllEvents();
571 ASSERT_EQ(1u, events1.size());
572 EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave"));
573
574 std::vector<XClientMessageEvent> events2 = collector2.PopAllEvents();
varkha 2014/05/07 03:11:08 Nit: Could use the same events vector for collecti
pkotwicz 2014/05/07 15:16:36 I think that keeping the vectors separate is clear
575 ASSERT_EQ(2u, events2.size());
576 EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter"));
577 EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition"));
578
579 client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy"));
580 client->OnMouseReleased();
581 events2 = collector2.PopAllEvents();
582 ASSERT_EQ(1u, events2.size());
583 EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop"));
584
585 EXPECT_TRUE(client->IsMoveLoopRunning());
586 client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy"));
587 EXPECT_FALSE(client->IsMoveLoopRunning());
588 }
589
590 } // namespace
591
592 // Test the behavior when the target changes during a drag.
593 TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) {
594 base::MessageLoop::current()->PostTask(
595 FROM_HERE,
596 base::Bind(&TargetChangesStep2, client()));
597 int result = StartDragAndDrop();
598 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
599 }
600
601 namespace {
602
603 void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
604 EXPECT_TRUE(client->IsMoveLoopRunning());
605
606 XID toplevel = 1;
607 ClientMessageEventCollector collector(toplevel, client);
608 client->SetTopmostXWindowAndMoveMouse(toplevel);
609
610 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
611 ASSERT_EQ(2u, events.size());
612 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
613 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
614
615 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
616 EXPECT_FALSE(collector.HasEvents());
617
618 // Send another mouse move such that there is a pending XdndPosition.
619 client->SetTopmostXWindowAndMoveMouse(toplevel);
620 events = collector.PopAllEvents();
621 ASSERT_EQ(1u, events.size());
622 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
623
624 client->OnMouseReleased();
625 // Reject the drop.
626 client->OnStatus(toplevel, false, None);
627
628 events = collector.PopAllEvents();
629 ASSERT_EQ(1u, events.size());
630 EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
631 EXPECT_FALSE(client->IsMoveLoopRunning());
632 }
633
634 void RejectAfterMouseReleaseStep3(TestDragDropClient* client) {
635 EXPECT_TRUE(client->IsMoveLoopRunning());
636
637 XID toplevel = 2;
638 ClientMessageEventCollector collector(toplevel, client);
639 client->SetTopmostXWindowAndMoveMouse(toplevel);
640
641 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
642 ASSERT_EQ(2u, events.size());
643 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
644 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
645
646 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
647 EXPECT_FALSE(collector.HasEvents());
648
649 client->OnMouseReleased();
650 events = collector.PopAllEvents();
651 ASSERT_EQ(1u, events.size());
652 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
653
654 EXPECT_TRUE(client->IsMoveLoopRunning());
655 client->OnFinished(toplevel, false, None);
656 EXPECT_FALSE(client->IsMoveLoopRunning());
657 }
658
659 } // namespace
660
661 // Test that the source sends XdndLeave instead of XdndDrop if the drag
662 // operation is rejected after the mouse is released.
663 TEST_F(DesktopDragDropClientAuraX11Test, RejectAfterMouseRelease) {
664 base::MessageLoop::current()->PostTask(
665 FROM_HERE,
666 base::Bind(&RejectAfterMouseReleaseStep2, client()));
667 int result = StartDragAndDrop();
668 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
669
670 // Repeat the test but reject the drop in the XdndFinished message instead.
671 base::MessageLoop::current()->PostTask(
672 FROM_HERE,
673 base::Bind(&RejectAfterMouseReleaseStep3, client()));
674 result = StartDragAndDrop();
675 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
676 }
677
678 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698