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 ~TestMoveLoop() override;
85 // Returns true if the move loop is running.
86 bool IsRunning() const;
89 bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) override;
90 void UpdateCursor(gfx::NativeCursor cursor) override;
91 void EndMoveLoop() override;
95 X11MoveLoopDelegate* delegate_;
97 // Ends the move loop.
98 base::Closure quit_closure_;
103 // Implementation of DesktopDragDropClientAuraX11 which works with a fake
104 // |DesktopDragDropClientAuraX11::source_current_window_|.
105 class TestDragDropClient : public DesktopDragDropClientAuraX11 {
107 // The location in screen coordinates used for the synthetic mouse moves
108 // generated in SetTopmostXWindowAndMoveMouse().
109 static const int kMouseMoveX;
110 static const int kMouseMoveY;
112 TestDragDropClient(aura::Window* window,
113 DesktopNativeCursorManager* cursor_manager);
114 ~TestDragDropClient() override;
116 // Returns the XID of the window which initiated the drag.
117 ::Window source_xwindow() {
121 // Returns the Atom with |name|.
122 Atom GetAtom(const char* name);
124 // Returns true if the event's message has |type|.
125 bool MessageHasType(const XClientMessageEvent& event,
128 // Sets |collector| to collect XClientMessageEvents which would otherwise
129 // have been sent to the drop target window.
130 void SetEventCollectorFor(::Window xid,
131 ClientMessageEventCollector* collector);
133 // Builds an XdndStatus message and sends it to
134 // DesktopDragDropClientAuraX11.
135 void OnStatus(XID target_window,
136 bool will_accept_drop,
137 ::Atom accepted_action);
139 // Builds an XdndFinished message and sends it to
140 // DesktopDragDropClientAuraX11.
141 void OnFinished(XID target_window,
143 ::Atom performed_action);
145 // Sets |xid| as the topmost window at the current mouse position and
146 // generates a synthetic mouse move.
147 void SetTopmostXWindowAndMoveMouse(::Window xid);
149 // Returns true if the move loop is running.
150 bool IsMoveLoopRunning();
153 // DesktopDragDropClientAuraX11:
154 scoped_ptr<X11MoveLoop> CreateMoveLoop(
155 X11MoveLoopDelegate* delegate) override;
156 ::Window FindWindowFor(const gfx::Point& screen_point) override;
157 void SendXClientEvent(::Window xid, XEvent* event) override;
159 // The XID of the window which initiated the drag.
160 ::Window source_xid_;
162 // The XID of the window which is simulated to be the topmost window at the
163 // current mouse position.
164 ::Window target_xid_;
166 // The move loop. Not owned.
169 // Map of ::Windows to the collector which intercepts XClientMessageEvents
171 std::map< ::Window, ClientMessageEventCollector*> collectors_;
173 ui::X11AtomCache atom_cache_;
175 DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
178 ///////////////////////////////////////////////////////////////////////////////
179 // ClientMessageEventCollector
181 ClientMessageEventCollector::ClientMessageEventCollector(
183 TestDragDropClient* client)
186 client->SetEventCollectorFor(xid, this);
189 ClientMessageEventCollector::~ClientMessageEventCollector() {
190 client_->SetEventCollectorFor(xid_, NULL);
193 std::vector<XClientMessageEvent> ClientMessageEventCollector::PopAllEvents() {
194 std::vector<XClientMessageEvent> to_return;
195 to_return.swap(events_);
199 void ClientMessageEventCollector::RecordEvent(
200 const XClientMessageEvent& event) {
201 events_.push_back(event);
204 ///////////////////////////////////////////////////////////////////////////////
207 TestMoveLoop::TestMoveLoop(X11MoveLoopDelegate* delegate)
208 : delegate_(delegate),
212 TestMoveLoop::~TestMoveLoop() {
215 bool TestMoveLoop::IsRunning() const {
219 bool TestMoveLoop::RunMoveLoop(
220 aura::Window* window,
221 gfx::NativeCursor cursor) {
223 base::RunLoop run_loop;
224 quit_closure_ = run_loop.QuitClosure();
229 void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
232 void TestMoveLoop::EndMoveLoop() {
234 delegate_->OnMoveLoopEnded();
240 ///////////////////////////////////////////////////////////////////////////////
241 // TestDragDropClient
244 const int TestDragDropClient::kMouseMoveX = 100;
247 const int TestDragDropClient::kMouseMoveY = 200;
249 TestDragDropClient::TestDragDropClient(
250 aura::Window* window,
251 DesktopNativeCursorManager* cursor_manager)
252 : DesktopDragDropClientAuraX11(window,
255 window->GetHost()->GetAcceleratedWidget()),
256 source_xid_(window->GetHost()->GetAcceleratedWidget()),
259 atom_cache_(gfx::GetXDisplay(), kAtomsToCache) {
262 TestDragDropClient::~TestDragDropClient() {
265 Atom TestDragDropClient::GetAtom(const char* name) {
266 return atom_cache_.GetAtom(name);
269 bool TestDragDropClient::MessageHasType(const XClientMessageEvent& event,
271 return event.message_type == atom_cache_.GetAtom(type);
274 void TestDragDropClient::SetEventCollectorFor(
276 ClientMessageEventCollector* collector) {
278 collectors_[xid] = collector;
280 collectors_.erase(xid);
283 void TestDragDropClient::OnStatus(XID target_window,
284 bool will_accept_drop,
285 ::Atom accepted_action) {
286 XClientMessageEvent event;
287 event.message_type = atom_cache_.GetAtom("XdndStatus");
289 event.window = source_xid_;
290 event.data.l[0] = target_window;
291 event.data.l[1] = will_accept_drop ? 1 : 0;
294 event.data.l[4] = accepted_action;
298 void TestDragDropClient::OnFinished(XID target_window,
300 ::Atom performed_action) {
301 XClientMessageEvent event;
302 event.message_type = atom_cache_.GetAtom("XdndFinished");
304 event.window = source_xid_;
305 event.data.l[0] = target_window;
306 event.data.l[1] = accepted_drop ? 1 : 0;
307 event.data.l[2] = performed_action;
310 OnXdndFinished(event);
313 void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
317 event.time = CurrentTime;
318 event.x_root = kMouseMoveX;
319 event.y_root = kMouseMoveY;
320 OnMouseMovement(&event);
323 bool TestDragDropClient::IsMoveLoopRunning() {
324 return loop_->IsRunning();
327 scoped_ptr<X11MoveLoop> TestDragDropClient::CreateMoveLoop(
328 X11MoveLoopDelegate* delegate) {
329 loop_ = new TestMoveLoop(delegate);
330 return scoped_ptr<X11MoveLoop>(loop_);
333 ::Window TestDragDropClient::FindWindowFor(const gfx::Point& screen_point) {
337 void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
338 std::map< ::Window, ClientMessageEventCollector*>::iterator it =
339 collectors_.find(xid);
340 if (it != collectors_.end())
341 it->second->RecordEvent(event->xclient);
346 class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
348 DesktopDragDropClientAuraX11Test() {
351 ~DesktopDragDropClientAuraX11Test() override {}
353 int StartDragAndDrop() {
354 ui::OSExchangeData data;
355 data.SetString(base::ASCIIToUTF16("Test"));
357 return client_->StartDragAndDrop(
359 widget_->GetNativeWindow()->GetRootWindow(),
360 widget_->GetNativeWindow(),
362 ui::DragDropTypes::DRAG_COPY,
363 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
367 void SetUp() override {
368 ViewsTestBase::SetUp();
370 // Create widget to initiate the drags.
371 widget_.reset(new Widget);
372 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
373 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
374 params.native_widget = new DesktopNativeWidgetAura(widget_.get());
375 params.bounds = gfx::Rect(100, 100);
376 widget_->Init(params);
379 cursor_manager_.reset(new DesktopNativeCursorManager(
380 DesktopCursorLoaderUpdater::Create()));
382 client_.reset(new TestDragDropClient(widget_->GetNativeWindow(),
383 cursor_manager_.get()));
387 void TearDown() override {
389 cursor_manager_.reset();
391 ViewsTestBase::TearDown();
394 TestDragDropClient* client() {
395 return client_.get();
399 scoped_ptr<TestDragDropClient> client_;
400 scoped_ptr<DesktopNativeCursorManager> cursor_manager_;
402 // The widget used to initiate drags.
403 scoped_ptr<Widget> widget_;
405 DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test);
410 void BasicStep2(TestDragDropClient* client, XID toplevel) {
411 EXPECT_TRUE(client->IsMoveLoopRunning());
413 ClientMessageEventCollector collector(toplevel, client);
414 client->SetTopmostXWindowAndMoveMouse(toplevel);
416 // XdndEnter should have been sent to |toplevel| before the XdndPosition
418 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
419 ASSERT_EQ(2u, events.size());
421 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
422 EXPECT_EQ(client->source_xwindow(),
423 static_cast<XID>(events[0].data.l[0]));
424 EXPECT_EQ(1, events[0].data.l[1] & 1);
425 std::vector<Atom> targets;
426 ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
427 EXPECT_FALSE(targets.empty());
429 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
430 EXPECT_EQ(client->source_xwindow(),
431 static_cast<XID>(events[0].data.l[0]));
433 TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY;
434 EXPECT_EQ(kCoords, events[1].data.l[2]);
435 EXPECT_EQ(client->GetAtom("XdndActionCopy"),
436 static_cast<Atom>(events[1].data.l[4]));
438 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
440 // Because there is no unprocessed XdndPosition, the drag drop client should
441 // send XdndDrop immediately after the mouse is released.
442 client->OnMouseReleased();
444 events = collector.PopAllEvents();
445 ASSERT_EQ(1u, events.size());
446 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
447 EXPECT_EQ(client->source_xwindow(),
448 static_cast<XID>(events[0].data.l[0]));
450 // Send XdndFinished to indicate that the drag drop client can cleanup any
451 // data related to this drag. The move loop should end only after the
452 // XdndFinished message was received.
453 EXPECT_TRUE(client->IsMoveLoopRunning());
454 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
455 EXPECT_FALSE(client->IsMoveLoopRunning());
458 void BasicStep3(TestDragDropClient* client, XID toplevel) {
459 EXPECT_TRUE(client->IsMoveLoopRunning());
461 ClientMessageEventCollector collector(toplevel, client);
462 client->SetTopmostXWindowAndMoveMouse(toplevel);
464 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
465 ASSERT_EQ(2u, events.size());
466 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
467 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
469 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
470 client->SetTopmostXWindowAndMoveMouse(toplevel);
471 events = collector.PopAllEvents();
472 ASSERT_EQ(1u, events.size());
473 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
475 // We have not received an XdndStatus ack for the second XdndPosition message.
476 // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
477 client->OnMouseReleased();
478 EXPECT_FALSE(collector.HasEvents());
480 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
481 events = collector.PopAllEvents();
482 ASSERT_EQ(1u, events.size());
483 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
485 EXPECT_TRUE(client->IsMoveLoopRunning());
486 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
487 EXPECT_FALSE(client->IsMoveLoopRunning());
492 TEST_F(DesktopDragDropClientAuraX11Test, Basic) {
495 base::MessageLoop::current()->PostTask(FROM_HERE,
496 base::Bind(&BasicStep2,
499 int result = StartDragAndDrop();
500 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
502 // Do another drag and drop to test that the data is properly cleaned up as a
503 // result of the XdndFinished message.
504 base::MessageLoop::current()->PostTask(FROM_HERE,
505 base::Bind(&BasicStep3,
508 result = StartDragAndDrop();
509 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
514 void TargetDoesNotRespondStep2(TestDragDropClient* client) {
515 EXPECT_TRUE(client->IsMoveLoopRunning());
518 ClientMessageEventCollector collector(toplevel, client);
519 client->SetTopmostXWindowAndMoveMouse(toplevel);
521 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
522 ASSERT_EQ(2u, events.size());
523 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
524 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
526 client->OnMouseReleased();
527 events = collector.PopAllEvents();
528 ASSERT_EQ(1u, events.size());
529 EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
530 EXPECT_FALSE(client->IsMoveLoopRunning());
535 // Test that we do not wait for the target to send XdndStatus if we have not
536 // received any XdndStatus messages at all from the target. The Unity
537 // DNDCollectionWindow is an example of an XdndAware target which does not
538 // respond to XdndPosition messages at all.
539 TEST_F(DesktopDragDropClientAuraX11Test, TargetDoesNotRespond) {
540 base::MessageLoop::current()->PostTask(
542 base::Bind(&TargetDoesNotRespondStep2, client()));
543 int result = StartDragAndDrop();
544 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
549 void QueuePositionStep2(TestDragDropClient* client) {
550 EXPECT_TRUE(client->IsMoveLoopRunning());
553 ClientMessageEventCollector collector(toplevel, client);
554 client->SetTopmostXWindowAndMoveMouse(toplevel);
555 client->SetTopmostXWindowAndMoveMouse(toplevel);
556 client->SetTopmostXWindowAndMoveMouse(toplevel);
558 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
559 ASSERT_EQ(2u, events.size());
560 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
561 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
563 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
564 events = collector.PopAllEvents();
565 ASSERT_EQ(1u, events.size());
566 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
568 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
569 EXPECT_FALSE(collector.HasEvents());
571 client->OnMouseReleased();
572 events = collector.PopAllEvents();
573 ASSERT_EQ(1u, events.size());
574 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
576 EXPECT_TRUE(client->IsMoveLoopRunning());
577 client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
578 EXPECT_FALSE(client->IsMoveLoopRunning());
583 // Test that XdndPosition messages are queued till the pending XdndPosition
584 // message is acked via an XdndStatus message.
585 TEST_F(DesktopDragDropClientAuraX11Test, QueuePosition) {
586 base::MessageLoop::current()->PostTask(
588 base::Bind(&QueuePositionStep2, client()));
589 int result = StartDragAndDrop();
590 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
595 void TargetChangesStep2(TestDragDropClient* client) {
596 EXPECT_TRUE(client->IsMoveLoopRunning());
599 ClientMessageEventCollector collector1(toplevel1, client);
600 client->SetTopmostXWindowAndMoveMouse(toplevel1);
602 std::vector<XClientMessageEvent> events1 = collector1.PopAllEvents();
603 ASSERT_EQ(2u, events1.size());
604 EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter"));
605 EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition"));
608 ClientMessageEventCollector collector2(toplevel2, client);
609 client->SetTopmostXWindowAndMoveMouse(toplevel2);
611 // It is possible for |toplevel1| to send XdndStatus after the source has sent
612 // XdndLeave but before |toplevel1| has received the XdndLeave message. The
613 // XdndStatus message should be ignored.
614 client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy"));
615 events1 = collector1.PopAllEvents();
616 ASSERT_EQ(1u, events1.size());
617 EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave"));
619 std::vector<XClientMessageEvent> events2 = collector2.PopAllEvents();
620 ASSERT_EQ(2u, events2.size());
621 EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter"));
622 EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition"));
624 client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy"));
625 client->OnMouseReleased();
626 events2 = collector2.PopAllEvents();
627 ASSERT_EQ(1u, events2.size());
628 EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop"));
630 EXPECT_TRUE(client->IsMoveLoopRunning());
631 client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy"));
632 EXPECT_FALSE(client->IsMoveLoopRunning());
637 // Test the behavior when the target changes during a drag.
638 TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) {
639 base::MessageLoop::current()->PostTask(
641 base::Bind(&TargetChangesStep2, client()));
642 int result = StartDragAndDrop();
643 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
648 void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
649 EXPECT_TRUE(client->IsMoveLoopRunning());
652 ClientMessageEventCollector collector(toplevel, client);
653 client->SetTopmostXWindowAndMoveMouse(toplevel);
655 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
656 ASSERT_EQ(2u, events.size());
657 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
658 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
660 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
661 EXPECT_FALSE(collector.HasEvents());
663 // Send another mouse move such that there is a pending XdndPosition.
664 client->SetTopmostXWindowAndMoveMouse(toplevel);
665 events = collector.PopAllEvents();
666 ASSERT_EQ(1u, events.size());
667 EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
669 client->OnMouseReleased();
671 client->OnStatus(toplevel, false, None);
673 events = collector.PopAllEvents();
674 ASSERT_EQ(1u, events.size());
675 EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
676 EXPECT_FALSE(client->IsMoveLoopRunning());
679 void RejectAfterMouseReleaseStep3(TestDragDropClient* client) {
680 EXPECT_TRUE(client->IsMoveLoopRunning());
683 ClientMessageEventCollector collector(toplevel, client);
684 client->SetTopmostXWindowAndMoveMouse(toplevel);
686 std::vector<XClientMessageEvent> events = collector.PopAllEvents();
687 ASSERT_EQ(2u, events.size());
688 EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
689 EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
691 client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
692 EXPECT_FALSE(collector.HasEvents());
694 client->OnMouseReleased();
695 events = collector.PopAllEvents();
696 ASSERT_EQ(1u, events.size());
697 EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
699 EXPECT_TRUE(client->IsMoveLoopRunning());
700 client->OnFinished(toplevel, false, None);
701 EXPECT_FALSE(client->IsMoveLoopRunning());
706 // Test that the source sends XdndLeave instead of XdndDrop if the drag
707 // operation is rejected after the mouse is released.
708 TEST_F(DesktopDragDropClientAuraX11Test, RejectAfterMouseRelease) {
709 base::MessageLoop::current()->PostTask(
711 base::Bind(&RejectAfterMouseReleaseStep2, client()));
712 int result = StartDragAndDrop();
713 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
715 // Repeat the test but reject the drop in the XdndFinished message instead.
716 base::MessageLoop::current()->PostTask(
718 base::Bind(&RejectAfterMouseReleaseStep3, client()));
719 result = StartDragAndDrop();
720 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);