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.
8 // Include views_test_base.h first because the definition of None in X.h
9 // conflicts with the definition of None in gtest-type-util.h
10 #include "ui/views/test/views_test_base.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/run_loop.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/desktop_aura/x11_move_loop.h"
26 #include "ui/views/widget/widget.h"
34 const char* kAtomsToCache
[] = {
46 class TestDragDropClient
;
48 // Collects messages which would otherwise be sent to |xid_| via
49 // SendXClientEvent().
50 class ClientMessageEventCollector
{
52 ClientMessageEventCollector(::Window xid
, TestDragDropClient
* client
);
53 virtual ~ClientMessageEventCollector();
55 // Returns true if |events_| is non-empty.
56 bool HasEvents() const {
57 return !events_
.empty();
60 // Pops all of |events_| and returns the popped events in the order that they
62 std::vector
<XClientMessageEvent
> PopAllEvents();
64 // Adds |event| to the stack.
65 void RecordEvent(const XClientMessageEvent
& event
);
71 TestDragDropClient
* client_
;
73 std::vector
<XClientMessageEvent
> events_
;
75 DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector
);
78 // An implementation of X11MoveLoop where RunMoveLoop() always starts the move
80 class TestMoveLoop
: public X11MoveLoop
{
82 explicit TestMoveLoop(X11MoveLoopDelegate
* delegate
);
83 virtual ~TestMoveLoop();
85 // Returns true if the move loop is running.
86 bool IsRunning() const;
89 virtual bool RunMoveLoop(aura::Window
* window
,
90 gfx::NativeCursor cursor
) OVERRIDE
;
91 virtual void UpdateCursor(gfx::NativeCursor cursor
) OVERRIDE
;
92 virtual void EndMoveLoop() OVERRIDE
;
96 X11MoveLoopDelegate
* delegate_
;
98 // Ends the move loop.
99 base::Closure quit_closure_
;
104 // Implementation of DesktopDragDropClientAuraX11 which works with a fake
105 // |DesktopDragDropClientAuraX11::source_current_window_|.
106 class TestDragDropClient
: public DesktopDragDropClientAuraX11
{
108 // The location in screen coordinates used for the synthetic mouse moves
109 // generated in SetTopmostXWindowAndMoveMouse().
110 static const int kMouseMoveX
;
111 static const int kMouseMoveY
;
113 TestDragDropClient(aura::Window
* window
,
114 DesktopNativeCursorManager
* cursor_manager
);
115 virtual ~TestDragDropClient();
117 // Returns the XID of the window which initiated the drag.
118 ::Window
source_xwindow() {
122 // Returns the Atom with |name|.
123 Atom
GetAtom(const char* name
);
125 // Returns true if the event's message has |type|.
126 bool MessageHasType(const XClientMessageEvent
& event
,
129 // Sets |collector| to collect XClientMessageEvents which would otherwise
130 // have been sent to the drop target window.
131 void SetEventCollectorFor(::Window xid
,
132 ClientMessageEventCollector
* collector
);
134 // Builds an XdndStatus message and sends it to
135 // DesktopDragDropClientAuraX11.
136 void OnStatus(XID target_window
,
137 bool will_accept_drop
,
138 ::Atom accepted_action
);
140 // Builds an XdndFinished message and sends it to
141 // DesktopDragDropClientAuraX11.
142 void OnFinished(XID target_window
,
144 ::Atom performed_action
);
146 // Sets |xid| as the topmost window at the current mouse position and
147 // generates a synthetic mouse move.
148 void SetTopmostXWindowAndMoveMouse(::Window xid
);
150 // Returns true if the move loop is running.
151 bool IsMoveLoopRunning();
154 // DesktopDragDropClientAuraX11:
155 virtual scoped_ptr
<X11MoveLoop
> CreateMoveLoop(
156 X11MoveLoopDelegate
* delegate
) OVERRIDE
;
157 virtual ::Window
FindWindowFor(const gfx::Point
& screen_point
) OVERRIDE
;
158 virtual void SendXClientEvent(::Window xid
, XEvent
* event
) OVERRIDE
;
160 // The XID of the window which initiated the drag.
161 ::Window source_xid_
;
163 // The XID of the window which is simulated to be the topmost window at the
164 // current mouse position.
165 ::Window target_xid_
;
167 // The move loop. Not owned.
170 // Map of ::Windows to the collector which intercepts XClientMessageEvents
172 std::map
< ::Window
, ClientMessageEventCollector
*> collectors_
;
174 ui::X11AtomCache atom_cache_
;
176 DISALLOW_COPY_AND_ASSIGN(TestDragDropClient
);
179 ///////////////////////////////////////////////////////////////////////////////
180 // ClientMessageEventCollector
182 ClientMessageEventCollector::ClientMessageEventCollector(
184 TestDragDropClient
* client
)
187 client
->SetEventCollectorFor(xid
, this);
190 ClientMessageEventCollector::~ClientMessageEventCollector() {
191 client_
->SetEventCollectorFor(xid_
, NULL
);
194 std::vector
<XClientMessageEvent
> ClientMessageEventCollector::PopAllEvents() {
195 std::vector
<XClientMessageEvent
> to_return
;
196 to_return
.swap(events_
);
200 void ClientMessageEventCollector::RecordEvent(
201 const XClientMessageEvent
& event
) {
202 events_
.push_back(event
);
205 ///////////////////////////////////////////////////////////////////////////////
208 TestMoveLoop::TestMoveLoop(X11MoveLoopDelegate
* delegate
)
209 : delegate_(delegate
),
213 TestMoveLoop::~TestMoveLoop() {
216 bool TestMoveLoop::IsRunning() const {
220 bool TestMoveLoop::RunMoveLoop(
221 aura::Window
* window
,
222 gfx::NativeCursor cursor
) {
224 base::RunLoop run_loop
;
225 quit_closure_
= run_loop
.QuitClosure();
230 void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor
) {
233 void TestMoveLoop::EndMoveLoop() {
235 delegate_
->OnMoveLoopEnded();
241 ///////////////////////////////////////////////////////////////////////////////
242 // TestDragDropClient
245 const int TestDragDropClient::kMouseMoveX
= 100;
248 const int TestDragDropClient::kMouseMoveY
= 200;
250 TestDragDropClient::TestDragDropClient(
251 aura::Window
* window
,
252 DesktopNativeCursorManager
* cursor_manager
)
253 : DesktopDragDropClientAuraX11(window
,
256 window
->GetHost()->GetAcceleratedWidget()),
257 source_xid_(window
->GetHost()->GetAcceleratedWidget()),
260 atom_cache_(gfx::GetXDisplay(), kAtomsToCache
) {
263 TestDragDropClient::~TestDragDropClient() {
266 Atom
TestDragDropClient::GetAtom(const char* name
) {
267 return atom_cache_
.GetAtom(name
);
270 bool TestDragDropClient::MessageHasType(const XClientMessageEvent
& event
,
272 return event
.message_type
== atom_cache_
.GetAtom(type
);
275 void TestDragDropClient::SetEventCollectorFor(
277 ClientMessageEventCollector
* collector
) {
279 collectors_
[xid
] = collector
;
281 collectors_
.erase(xid
);
284 void TestDragDropClient::OnStatus(XID target_window
,
285 bool will_accept_drop
,
286 ::Atom accepted_action
) {
287 XClientMessageEvent event
;
288 event
.message_type
= atom_cache_
.GetAtom("XdndStatus");
290 event
.window
= source_xid_
;
291 event
.data
.l
[0] = target_window
;
292 event
.data
.l
[1] = will_accept_drop
? 1 : 0;
295 event
.data
.l
[4] = accepted_action
;
299 void TestDragDropClient::OnFinished(XID target_window
,
301 ::Atom performed_action
) {
302 XClientMessageEvent event
;
303 event
.message_type
= atom_cache_
.GetAtom("XdndFinished");
305 event
.window
= source_xid_
;
306 event
.data
.l
[0] = target_window
;
307 event
.data
.l
[1] = accepted_drop
? 1 : 0;
308 event
.data
.l
[2] = performed_action
;
311 OnXdndFinished(event
);
314 void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid
) {
318 event
.time
= CurrentTime
;
319 event
.x_root
= kMouseMoveX
;
320 event
.y_root
= kMouseMoveY
;
321 OnMouseMovement(&event
);
324 bool TestDragDropClient::IsMoveLoopRunning() {
325 return loop_
->IsRunning();
328 scoped_ptr
<X11MoveLoop
> TestDragDropClient::CreateMoveLoop(
329 X11MoveLoopDelegate
* delegate
) {
330 loop_
= new TestMoveLoop(delegate
);
331 return scoped_ptr
<X11MoveLoop
>(loop_
);
334 ::Window
TestDragDropClient::FindWindowFor(const gfx::Point
& screen_point
) {
338 void TestDragDropClient::SendXClientEvent(::Window xid
, XEvent
* event
) {
339 std::map
< ::Window
, ClientMessageEventCollector
*>::iterator it
=
340 collectors_
.find(xid
);
341 if (it
!= collectors_
.end())
342 it
->second
->RecordEvent(event
->xclient
);
347 class DesktopDragDropClientAuraX11Test
: public ViewsTestBase
{
349 DesktopDragDropClientAuraX11Test() {
352 virtual ~DesktopDragDropClientAuraX11Test() {
355 int StartDragAndDrop() {
356 ui::OSExchangeData data
;
357 data
.SetString(base::ASCIIToUTF16("Test"));
359 return client_
->StartDragAndDrop(
361 widget_
->GetNativeWindow()->GetRootWindow(),
362 widget_
->GetNativeWindow(),
364 ui::DragDropTypes::DRAG_COPY
,
365 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
369 virtual void SetUp() OVERRIDE
{
370 ViewsTestBase::SetUp();
372 // Create widget to initiate the drags.
373 widget_
.reset(new Widget
);
374 Widget::InitParams
params(Widget::InitParams::TYPE_WINDOW
);
375 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
376 params
.native_widget
= new DesktopNativeWidgetAura(widget_
.get());
377 params
.bounds
= gfx::Rect(100, 100);
378 widget_
->Init(params
);
381 cursor_manager_
.reset(new DesktopNativeCursorManager(
382 DesktopCursorLoaderUpdater::Create()));
384 client_
.reset(new TestDragDropClient(widget_
->GetNativeWindow(),
385 cursor_manager_
.get()));
389 virtual void TearDown() OVERRIDE
{
391 cursor_manager_
.reset();
393 ViewsTestBase::TearDown();
396 TestDragDropClient
* client() {
397 return client_
.get();
401 scoped_ptr
<TestDragDropClient
> client_
;
402 scoped_ptr
<DesktopNativeCursorManager
> cursor_manager_
;
404 // The widget used to initiate drags.
405 scoped_ptr
<Widget
> widget_
;
407 DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test
);
412 void BasicStep2(TestDragDropClient
* client
, XID toplevel
) {
413 EXPECT_TRUE(client
->IsMoveLoopRunning());
415 ClientMessageEventCollector
collector(toplevel
, client
);
416 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
418 // XdndEnter should have been sent to |toplevel| before the XdndPosition
420 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
421 ASSERT_EQ(2u, events
.size());
423 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
424 EXPECT_EQ(client
->source_xwindow(),
425 static_cast<XID
>(events
[0].data
.l
[0]));
426 EXPECT_EQ(1, events
[0].data
.l
[1] & 1);
427 std::vector
<Atom
> targets
;
428 ui::GetAtomArrayProperty(client
->source_xwindow(), "XdndTypeList", &targets
);
429 EXPECT_FALSE(targets
.empty());
431 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
432 EXPECT_EQ(client
->source_xwindow(),
433 static_cast<XID
>(events
[0].data
.l
[0]));
435 TestDragDropClient::kMouseMoveX
<< 16 | TestDragDropClient::kMouseMoveY
;
436 EXPECT_EQ(kCoords
, events
[1].data
.l
[2]);
437 EXPECT_EQ(client
->GetAtom("XdndActionCopy"),
438 static_cast<Atom
>(events
[1].data
.l
[4]));
440 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
442 // Because there is no unprocessed XdndPosition, the drag drop client should
443 // send XdndDrop immediately after the mouse is released.
444 client
->OnMouseReleased();
446 events
= collector
.PopAllEvents();
447 ASSERT_EQ(1u, events
.size());
448 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndDrop"));
449 EXPECT_EQ(client
->source_xwindow(),
450 static_cast<XID
>(events
[0].data
.l
[0]));
452 // Send XdndFinished to indicate that the drag drop client can cleanup any
453 // data related to this drag. The move loop should end only after the
454 // XdndFinished message was received.
455 EXPECT_TRUE(client
->IsMoveLoopRunning());
456 client
->OnFinished(toplevel
, true, client
->GetAtom("XdndActionCopy"));
457 EXPECT_FALSE(client
->IsMoveLoopRunning());
460 void BasicStep3(TestDragDropClient
* client
, XID toplevel
) {
461 EXPECT_TRUE(client
->IsMoveLoopRunning());
463 ClientMessageEventCollector
collector(toplevel
, client
);
464 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
466 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
467 ASSERT_EQ(2u, events
.size());
468 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
469 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
471 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
472 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
473 events
= collector
.PopAllEvents();
474 ASSERT_EQ(1u, events
.size());
475 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndPosition"));
477 // We have not received an XdndStatus ack for the second XdndPosition message.
478 // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
479 client
->OnMouseReleased();
480 EXPECT_FALSE(collector
.HasEvents());
482 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
483 events
= collector
.PopAllEvents();
484 ASSERT_EQ(1u, events
.size());
485 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndDrop"));
487 EXPECT_TRUE(client
->IsMoveLoopRunning());
488 client
->OnFinished(toplevel
, true, client
->GetAtom("XdndActionCopy"));
489 EXPECT_FALSE(client
->IsMoveLoopRunning());
494 TEST_F(DesktopDragDropClientAuraX11Test
, Basic
) {
497 base::MessageLoop::current()->PostTask(FROM_HERE
,
498 base::Bind(&BasicStep2
,
501 int result
= StartDragAndDrop();
502 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY
, result
);
504 // Do another drag and drop to test that the data is properly cleaned up as a
505 // result of the XdndFinished message.
506 base::MessageLoop::current()->PostTask(FROM_HERE
,
507 base::Bind(&BasicStep3
,
510 result
= StartDragAndDrop();
511 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY
, result
);
516 void TargetDoesNotRespondStep2(TestDragDropClient
* client
) {
517 EXPECT_TRUE(client
->IsMoveLoopRunning());
520 ClientMessageEventCollector
collector(toplevel
, client
);
521 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
523 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
524 ASSERT_EQ(2u, events
.size());
525 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
526 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
528 client
->OnMouseReleased();
529 events
= collector
.PopAllEvents();
530 ASSERT_EQ(1u, events
.size());
531 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndLeave"));
532 EXPECT_FALSE(client
->IsMoveLoopRunning());
537 // Test that we do not wait for the target to send XdndStatus if we have not
538 // received any XdndStatus messages at all from the target. The Unity
539 // DNDCollectionWindow is an example of an XdndAware target which does not
540 // respond to XdndPosition messages at all.
541 TEST_F(DesktopDragDropClientAuraX11Test
, TargetDoesNotRespond
) {
542 base::MessageLoop::current()->PostTask(
544 base::Bind(&TargetDoesNotRespondStep2
, client()));
545 int result
= StartDragAndDrop();
546 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE
, result
);
551 void QueuePositionStep2(TestDragDropClient
* client
) {
552 EXPECT_TRUE(client
->IsMoveLoopRunning());
555 ClientMessageEventCollector
collector(toplevel
, client
);
556 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
557 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
558 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
560 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
561 ASSERT_EQ(2u, events
.size());
562 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
563 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
565 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
566 events
= collector
.PopAllEvents();
567 ASSERT_EQ(1u, events
.size());
568 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndPosition"));
570 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
571 EXPECT_FALSE(collector
.HasEvents());
573 client
->OnMouseReleased();
574 events
= collector
.PopAllEvents();
575 ASSERT_EQ(1u, events
.size());
576 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndDrop"));
578 EXPECT_TRUE(client
->IsMoveLoopRunning());
579 client
->OnFinished(toplevel
, true, client
->GetAtom("XdndActionCopy"));
580 EXPECT_FALSE(client
->IsMoveLoopRunning());
585 // Test that XdndPosition messages are queued till the pending XdndPosition
586 // message is acked via an XdndStatus message.
587 TEST_F(DesktopDragDropClientAuraX11Test
, QueuePosition
) {
588 base::MessageLoop::current()->PostTask(
590 base::Bind(&QueuePositionStep2
, client()));
591 int result
= StartDragAndDrop();
592 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY
, result
);
597 void TargetChangesStep2(TestDragDropClient
* client
) {
598 EXPECT_TRUE(client
->IsMoveLoopRunning());
601 ClientMessageEventCollector
collector1(toplevel1
, client
);
602 client
->SetTopmostXWindowAndMoveMouse(toplevel1
);
604 std::vector
<XClientMessageEvent
> events1
= collector1
.PopAllEvents();
605 ASSERT_EQ(2u, events1
.size());
606 EXPECT_TRUE(client
->MessageHasType(events1
[0], "XdndEnter"));
607 EXPECT_TRUE(client
->MessageHasType(events1
[1], "XdndPosition"));
610 ClientMessageEventCollector
collector2(toplevel2
, client
);
611 client
->SetTopmostXWindowAndMoveMouse(toplevel2
);
613 // It is possible for |toplevel1| to send XdndStatus after the source has sent
614 // XdndLeave but before |toplevel1| has received the XdndLeave message. The
615 // XdndStatus message should be ignored.
616 client
->OnStatus(toplevel1
, true, client
->GetAtom("XdndActionCopy"));
617 events1
= collector1
.PopAllEvents();
618 ASSERT_EQ(1u, events1
.size());
619 EXPECT_TRUE(client
->MessageHasType(events1
[0], "XdndLeave"));
621 std::vector
<XClientMessageEvent
> events2
= collector2
.PopAllEvents();
622 ASSERT_EQ(2u, events2
.size());
623 EXPECT_TRUE(client
->MessageHasType(events2
[0], "XdndEnter"));
624 EXPECT_TRUE(client
->MessageHasType(events2
[1], "XdndPosition"));
626 client
->OnStatus(toplevel2
, true, client
->GetAtom("XdndActionCopy"));
627 client
->OnMouseReleased();
628 events2
= collector2
.PopAllEvents();
629 ASSERT_EQ(1u, events2
.size());
630 EXPECT_TRUE(client
->MessageHasType(events2
[0], "XdndDrop"));
632 EXPECT_TRUE(client
->IsMoveLoopRunning());
633 client
->OnFinished(toplevel2
, true, client
->GetAtom("XdndActionCopy"));
634 EXPECT_FALSE(client
->IsMoveLoopRunning());
639 // Test the behavior when the target changes during a drag.
640 TEST_F(DesktopDragDropClientAuraX11Test
, TargetChanges
) {
641 base::MessageLoop::current()->PostTask(
643 base::Bind(&TargetChangesStep2
, client()));
644 int result
= StartDragAndDrop();
645 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY
, result
);
650 void RejectAfterMouseReleaseStep2(TestDragDropClient
* client
) {
651 EXPECT_TRUE(client
->IsMoveLoopRunning());
654 ClientMessageEventCollector
collector(toplevel
, client
);
655 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
657 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
658 ASSERT_EQ(2u, events
.size());
659 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
660 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
662 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
663 EXPECT_FALSE(collector
.HasEvents());
665 // Send another mouse move such that there is a pending XdndPosition.
666 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
667 events
= collector
.PopAllEvents();
668 ASSERT_EQ(1u, events
.size());
669 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndPosition"));
671 client
->OnMouseReleased();
673 client
->OnStatus(toplevel
, false, None
);
675 events
= collector
.PopAllEvents();
676 ASSERT_EQ(1u, events
.size());
677 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndLeave"));
678 EXPECT_FALSE(client
->IsMoveLoopRunning());
681 void RejectAfterMouseReleaseStep3(TestDragDropClient
* client
) {
682 EXPECT_TRUE(client
->IsMoveLoopRunning());
685 ClientMessageEventCollector
collector(toplevel
, client
);
686 client
->SetTopmostXWindowAndMoveMouse(toplevel
);
688 std::vector
<XClientMessageEvent
> events
= collector
.PopAllEvents();
689 ASSERT_EQ(2u, events
.size());
690 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndEnter"));
691 EXPECT_TRUE(client
->MessageHasType(events
[1], "XdndPosition"));
693 client
->OnStatus(toplevel
, true, client
->GetAtom("XdndActionCopy"));
694 EXPECT_FALSE(collector
.HasEvents());
696 client
->OnMouseReleased();
697 events
= collector
.PopAllEvents();
698 ASSERT_EQ(1u, events
.size());
699 EXPECT_TRUE(client
->MessageHasType(events
[0], "XdndDrop"));
701 EXPECT_TRUE(client
->IsMoveLoopRunning());
702 client
->OnFinished(toplevel
, false, None
);
703 EXPECT_FALSE(client
->IsMoveLoopRunning());
708 // Test that the source sends XdndLeave instead of XdndDrop if the drag
709 // operation is rejected after the mouse is released.
710 TEST_F(DesktopDragDropClientAuraX11Test
, RejectAfterMouseRelease
) {
711 base::MessageLoop::current()->PostTask(
713 base::Bind(&RejectAfterMouseReleaseStep2
, client()));
714 int result
= StartDragAndDrop();
715 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE
, result
);
717 // Repeat the test but reject the drop in the XdndFinished message instead.
718 base::MessageLoop::current()->PostTask(
720 base::Bind(&RejectAfterMouseReleaseStep3
, client()));
721 result
= StartDragAndDrop();
722 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE
, result
);