Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_drag_drop_client_aurax11_unittest.cc
blob1008289d1d9e4d40563e523592f4f9613733b9bf
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.
5 #include <map>
6 #include <vector>
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"
28 #include <X11/Xlib.h>
30 namespace views {
32 namespace {
34 const char* kAtomsToCache[] = {
35 "XdndActionCopy",
36 "XdndDrop",
37 "XdndEnter",
38 "XdndFinished",
39 "XdndLeave",
40 "XdndPosition",
41 "XdndStatus",
42 "XdndTypeList",
43 NULL
46 class TestDragDropClient;
48 // Collects messages which would otherwise be sent to |xid_| via
49 // SendXClientEvent().
50 class ClientMessageEventCollector {
51 public:
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
61 // were on the stack
62 std::vector<XClientMessageEvent> PopAllEvents();
64 // Adds |event| to the stack.
65 void RecordEvent(const XClientMessageEvent& event);
67 private:
68 ::Window xid_;
70 // Not owned.
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
79 // loop.
80 class TestMoveLoop : public X11MoveLoop {
81 public:
82 explicit TestMoveLoop(X11MoveLoopDelegate* delegate);
83 virtual ~TestMoveLoop();
85 // Returns true if the move loop is running.
86 bool IsRunning() const;
88 // X11MoveLoop:
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;
94 private:
95 // Not owned.
96 X11MoveLoopDelegate* delegate_;
98 // Ends the move loop.
99 base::Closure quit_closure_;
101 bool is_running_;
104 // Implementation of DesktopDragDropClientAuraX11 which works with a fake
105 // |DesktopDragDropClientAuraX11::source_current_window_|.
106 class TestDragDropClient : public DesktopDragDropClientAuraX11 {
107 public:
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() {
119 return source_xid_;
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,
127 const char* type);
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,
143 bool accepted_drop,
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();
153 private:
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.
168 TestMoveLoop* loop_;
170 // Map of ::Windows to the collector which intercepts XClientMessageEvents
171 // for that window.
172 std::map< ::Window, ClientMessageEventCollector*> collectors_;
174 ui::X11AtomCache atom_cache_;
176 DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
179 ///////////////////////////////////////////////////////////////////////////////
180 // ClientMessageEventCollector
182 ClientMessageEventCollector::ClientMessageEventCollector(
183 ::Window xid,
184 TestDragDropClient* client)
185 : xid_(xid),
186 client_(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_);
197 return to_return;
200 void ClientMessageEventCollector::RecordEvent(
201 const XClientMessageEvent& event) {
202 events_.push_back(event);
205 ///////////////////////////////////////////////////////////////////////////////
206 // TestMoveLoop
208 TestMoveLoop::TestMoveLoop(X11MoveLoopDelegate* delegate)
209 : delegate_(delegate),
210 is_running_(false) {
213 TestMoveLoop::~TestMoveLoop() {
216 bool TestMoveLoop::IsRunning() const {
217 return is_running_;
220 bool TestMoveLoop::RunMoveLoop(
221 aura::Window* window,
222 gfx::NativeCursor cursor) {
223 is_running_ = true;
224 base::RunLoop run_loop;
225 quit_closure_ = run_loop.QuitClosure();
226 run_loop.Run();
227 return true;
230 void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
233 void TestMoveLoop::EndMoveLoop() {
234 if (is_running_) {
235 delegate_->OnMoveLoopEnded();
236 is_running_ = false;
237 quit_closure_.Run();
241 ///////////////////////////////////////////////////////////////////////////////
242 // TestDragDropClient
244 // static
245 const int TestDragDropClient::kMouseMoveX = 100;
247 // static
248 const int TestDragDropClient::kMouseMoveY = 200;
250 TestDragDropClient::TestDragDropClient(
251 aura::Window* window,
252 DesktopNativeCursorManager* cursor_manager)
253 : DesktopDragDropClientAuraX11(window,
254 cursor_manager,
255 gfx::GetXDisplay(),
256 window->GetHost()->GetAcceleratedWidget()),
257 source_xid_(window->GetHost()->GetAcceleratedWidget()),
258 target_xid_(None),
259 loop_(NULL),
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,
271 const char* type) {
272 return event.message_type == atom_cache_.GetAtom(type);
275 void TestDragDropClient::SetEventCollectorFor(
276 ::Window xid,
277 ClientMessageEventCollector* collector) {
278 if (collector)
279 collectors_[xid] = collector;
280 else
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");
289 event.format = 32;
290 event.window = source_xid_;
291 event.data.l[0] = target_window;
292 event.data.l[1] = will_accept_drop ? 1 : 0;
293 event.data.l[2] = 0;
294 event.data.l[3] = 0;
295 event.data.l[4] = accepted_action;
296 OnXdndStatus(event);
299 void TestDragDropClient::OnFinished(XID target_window,
300 bool accepted_drop,
301 ::Atom performed_action) {
302 XClientMessageEvent event;
303 event.message_type = atom_cache_.GetAtom("XdndFinished");
304 event.format = 32;
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;
309 event.data.l[3] = 0;
310 event.data.l[4] = 0;
311 OnXdndFinished(event);
314 void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
315 target_xid_ = xid;
317 XMotionEvent event;
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) {
335 return target_xid_;
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);
345 } // namespace
347 class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
348 public:
349 DesktopDragDropClientAuraX11Test() {
352 virtual ~DesktopDragDropClientAuraX11Test() {
355 int StartDragAndDrop() {
356 ui::OSExchangeData data;
357 data.SetString(base::ASCIIToUTF16("Test"));
359 return client_->StartDragAndDrop(
360 data,
361 widget_->GetNativeWindow()->GetRootWindow(),
362 widget_->GetNativeWindow(),
363 gfx::Point(),
364 ui::DragDropTypes::DRAG_COPY,
365 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
368 // ViewsTestBase:
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);
379 widget_->Show();
381 cursor_manager_.reset(new DesktopNativeCursorManager(
382 DesktopCursorLoaderUpdater::Create()));
384 client_.reset(new TestDragDropClient(widget_->GetNativeWindow(),
385 cursor_manager_.get()));
386 client_->Init();
389 virtual void TearDown() OVERRIDE {
390 client_.reset();
391 cursor_manager_.reset();
392 widget_.reset();
393 ViewsTestBase::TearDown();
396 TestDragDropClient* client() {
397 return client_.get();
400 private:
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);
410 namespace {
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
419 // message.
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]));
434 const long kCoords =
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());
492 } // namespace
494 TEST_F(DesktopDragDropClientAuraX11Test, Basic) {
495 XID toplevel = 1;
497 base::MessageLoop::current()->PostTask(FROM_HERE,
498 base::Bind(&BasicStep2,
499 client(),
500 toplevel));
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,
508 client(),
509 toplevel));
510 result = StartDragAndDrop();
511 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
514 namespace {
516 void TargetDoesNotRespondStep2(TestDragDropClient* client) {
517 EXPECT_TRUE(client->IsMoveLoopRunning());
519 XID toplevel = 1;
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());
535 } // namespace
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(
543 FROM_HERE,
544 base::Bind(&TargetDoesNotRespondStep2, client()));
545 int result = StartDragAndDrop();
546 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
549 namespace {
551 void QueuePositionStep2(TestDragDropClient* client) {
552 EXPECT_TRUE(client->IsMoveLoopRunning());
554 XID toplevel = 1;
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());
583 } // namespace
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(
589 FROM_HERE,
590 base::Bind(&QueuePositionStep2, client()));
591 int result = StartDragAndDrop();
592 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
595 namespace {
597 void TargetChangesStep2(TestDragDropClient* client) {
598 EXPECT_TRUE(client->IsMoveLoopRunning());
600 XID toplevel1 = 1;
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"));
609 XID toplevel2 = 2;
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());
637 } // namespace
639 // Test the behavior when the target changes during a drag.
640 TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) {
641 base::MessageLoop::current()->PostTask(
642 FROM_HERE,
643 base::Bind(&TargetChangesStep2, client()));
644 int result = StartDragAndDrop();
645 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
648 namespace {
650 void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
651 EXPECT_TRUE(client->IsMoveLoopRunning());
653 XID toplevel = 1;
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();
672 // Reject the drop.
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());
684 XID toplevel = 2;
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());
706 } // namespace
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(
712 FROM_HERE,
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(
719 FROM_HERE,
720 base::Bind(&RejectAfterMouseReleaseStep3, client()));
721 result = StartDragAndDrop();
722 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
725 } // namespace views