Index: ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc |
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..315356ad97a4a601234a4457348eb9419af29afc |
--- /dev/null |
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc |
@@ -0,0 +1,678 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <map> |
+#include <vector> |
+#include <X11/Xlib.h> |
+ |
+// Include views_test_base.h first because the definition of None in X.h |
+// conflicts with the definition of None in gtest-type-util.h |
+#include "ui/views/test/views_test_base.h" |
+ |
+#include "base/memory/scoped_ptr.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "ui/aura/window.h" |
+#include "ui/aura/window_tree_host.h" |
+#include "ui/base/dragdrop/os_exchange_data.h" |
+#include "ui/base/x/x11_util.h" |
+#include "ui/gfx/x/x11_atom_cache.h" |
+#include "ui/gfx/x/x11_types.h" |
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h" |
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" |
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" |
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" |
+#include "ui/views/widget/widget.h" |
+ |
+namespace views { |
+ |
+namespace { |
+ |
+const char* kAtomsToCache[] = { |
+ "XdndActionCopy", |
+ "XdndDrop", |
+ "XdndEnter", |
+ "XdndFinished", |
+ "XdndLeave", |
+ "XdndPosition", |
+ "XdndStatus", |
+ "XdndTypeList", |
+ NULL |
+}; |
+ |
+class TestDragDropClient; |
+ |
+// Collects messages which would otherwise be sent to |xid_| via |
+// SendXClientEvent(). |
+class ClientMessageEventCollector { |
+ public: |
+ ClientMessageEventCollector(::Window xid, TestDragDropClient* client); |
+ virtual ~ClientMessageEventCollector(); |
+ |
+ // Returns true if |events_| is non-empty. |
+ bool HasEvents() const { |
+ return !events_.empty(); |
+ } |
+ |
+ // Pops all of |events_| and returns the popped events in the order that they |
+ // were on the stack |
+ std::vector<XClientMessageEvent> PopAllEvents(); |
+ |
+ // Adds |event| to the stack. |
+ void RecordEvent(const XClientMessageEvent& event); |
+ |
+ private: |
+ ::Window xid_; |
+ |
+ // Not owned. |
+ TestDragDropClient* client_; |
+ |
+ std::vector<XClientMessageEvent> events_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector); |
+}; |
+ |
+// Implementation of DesktopDragDropClientAuraX11 which works with a fake |
+// |DesktopDragDropClientAuraX11::source_current_window_|. |
+class TestDragDropClient : public DesktopDragDropClientAuraX11 { |
+ public: |
+ // The location in screen coordinates used for the synthetic mouse moves |
+ // generated in SetTopmostXWindowAndMoveMouse(). |
+ static const int kMouseMoveX; |
+ static const int kMouseMoveY; |
+ |
+ TestDragDropClient(aura::Window* window, |
+ DesktopNativeCursorManager* cursor_manager); |
+ virtual ~TestDragDropClient(); |
+ |
+ // Returns the XID of the window which initiated the drag. |
+ ::Window source_xwindow() { |
+ return source_xid_; |
+ } |
+ |
+ // Returns the Atom with |name|. |
+ Atom GetAtom(const char* name); |
+ |
+ // Returns true if the event's message has |type|. |
+ bool MessageHasType(const XClientMessageEvent& event, |
+ const char* type); |
+ |
+ // Sets |collector| to collect XClientMessageEvents which would otherwise |
+ // have been sent to the drop target window. |
+ void SetEventCollectorFor(::Window xid, |
+ ClientMessageEventCollector* collector); |
+ |
+ // Builds an XdndStatus message and sends it to |
+ // DesktopDragDropClientAuraX11. |
+ void OnStatus(XID target_window, |
+ bool will_accept_drop, |
+ ::Atom accepted_action); |
+ |
+ // Builds an XdndFinished message and sends it to |
+ // DesktopDragDropClientAuraX11. |
+ void OnFinished(XID target_window, |
+ bool accepted_drop, |
+ ::Atom performed_action); |
+ |
+ // Sets |xid| as the topmost window at the current mouse position and |
+ // generates a synthetic mouse move. |
+ void SetTopmostXWindowAndMoveMouse(::Window xid); |
+ |
+ // Returns true if the move loop is running. |
+ bool IsMoveLoopRunning(); |
+ |
+ // DesktopDragDropClientAuraX11: |
+ virtual int StartDragAndDrop( |
+ const ui::OSExchangeData& data, |
+ aura::Window* root_window, |
+ aura::Window* source_window, |
+ const gfx::Point& root_location, |
+ int operation, |
+ ui::DragDropTypes::DragEventSource source) OVERRIDE; |
+ virtual void OnMoveLoopEnded() OVERRIDE; |
+ |
+ private: |
+ // DesktopDragDropClientAuraX11: |
+ virtual ::Window FindWindowFor(const gfx::Point& screen_point) OVERRIDE; |
+ virtual void SendXClientEvent(::Window xid, XEvent* event) OVERRIDE; |
+ |
+ // The XID of the window which initiated the drag. |
+ ::Window source_xid_; |
+ |
+ // The XID of the window which is simulated to be the topmost window at the |
+ // current mouse position. |
+ ::Window target_xid_; |
+ |
+ // Whether the move loop is running. |
+ bool move_loop_running_; |
+ |
+ // Map of ::Windows to the collector which intercepts XClientMessageEvents |
+ // for that window. |
+ std::map<::Window, ClientMessageEventCollector*> collectors_; |
+ |
+ ui::X11AtomCache atom_cache_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropClient); |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// ClientMessageEventCollector |
+ |
+ClientMessageEventCollector::ClientMessageEventCollector( |
+ ::Window xid, |
+ TestDragDropClient* client) |
+ : xid_(xid), |
+ client_(client) { |
+ client->SetEventCollectorFor(xid, this); |
+} |
+ |
+ClientMessageEventCollector::~ClientMessageEventCollector() { |
+ client_->SetEventCollectorFor(xid_, NULL); |
+} |
+ |
+std::vector<XClientMessageEvent> ClientMessageEventCollector::PopAllEvents() { |
+ std::vector<XClientMessageEvent> to_return; |
+ to_return.swap(events_); |
+ return to_return; |
+} |
+ |
+void ClientMessageEventCollector::RecordEvent( |
+ const XClientMessageEvent& event) { |
+ events_.push_back(event); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// TestDragDropClient |
+ |
+// static |
+const int TestDragDropClient::kMouseMoveX = 100; |
+ |
+// static |
+const int TestDragDropClient::kMouseMoveY = 200; |
+ |
+TestDragDropClient::TestDragDropClient( |
+ aura::Window* window, |
+ DesktopNativeCursorManager* cursor_manager) |
+ : DesktopDragDropClientAuraX11(window, |
+ cursor_manager, |
+ gfx::GetXDisplay(), |
+ window->GetHost()->GetAcceleratedWidget()), |
+ source_xid_(window->GetHost()->GetAcceleratedWidget()), |
+ target_xid_(None), |
+ move_loop_running_(false), |
+ atom_cache_(gfx::GetXDisplay(), kAtomsToCache) { |
+} |
+ |
+TestDragDropClient::~TestDragDropClient() { |
+} |
+ |
+Atom TestDragDropClient::GetAtom(const char* name) { |
+ return atom_cache_.GetAtom(name); |
+} |
+ |
+bool TestDragDropClient::MessageHasType(const XClientMessageEvent& event, |
+ const char* type) { |
+ return event.message_type == atom_cache_.GetAtom(type); |
+} |
+ |
+void TestDragDropClient::SetEventCollectorFor( |
+ ::Window xid, |
+ ClientMessageEventCollector* collector) { |
+ if (collector) |
+ collectors_[xid] = collector; |
+ else |
+ collectors_.erase(xid); |
+} |
+ |
+void TestDragDropClient::OnStatus(XID target_window, |
+ bool will_accept_drop, |
+ ::Atom accepted_action) { |
+ XClientMessageEvent event; |
+ event.message_type = atom_cache_.GetAtom("XdndStatus"); |
+ event.format = 32; |
+ event.window = source_xid_; |
+ event.data.l[0] = target_window; |
+ event.data.l[1] = will_accept_drop ? 1 : 0; |
+ event.data.l[2] = 0; |
+ event.data.l[3] = 0; |
+ event.data.l[4] = accepted_action; |
+ OnXdndStatus(event); |
+} |
+ |
+void TestDragDropClient::OnFinished(XID target_window, |
+ bool accepted_drop, |
+ ::Atom performed_action) { |
+ XClientMessageEvent event; |
+ event.message_type = atom_cache_.GetAtom("XdndFinished"); |
+ event.format = 32; |
+ event.window = source_xid_; |
+ event.data.l[0] = target_window; |
+ event.data.l[1] = accepted_drop ? 1 : 0; |
+ event.data.l[2] = performed_action; |
+ event.data.l[3] = 0; |
+ event.data.l[4] = 0; |
+ OnXdndFinished(event); |
+} |
+ |
+void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) { |
+ target_xid_ = xid; |
+ |
+ XMotionEvent event; |
+ event.time = CurrentTime; |
+ event.x_root = kMouseMoveX; |
+ event.y_root = kMouseMoveY; |
+ OnMouseMovement(&event); |
+} |
+ |
+bool TestDragDropClient::IsMoveLoopRunning() { |
+ return move_loop_running_; |
+} |
+ |
+int TestDragDropClient::StartDragAndDrop( |
+ const ui::OSExchangeData& data, |
+ aura::Window* root_window, |
+ aura::Window* source_window, |
+ const gfx::Point& root_location, |
+ int operation, |
+ ui::DragDropTypes::DragEventSource source) { |
+ move_loop_running_ = true; |
+ return DesktopDragDropClientAuraX11::StartDragAndDrop(data, root_window, |
+ source_window, root_location, operation, source); |
+} |
+ |
+void TestDragDropClient::OnMoveLoopEnded() { |
+ DesktopDragDropClientAuraX11::OnMoveLoopEnded(); |
+ move_loop_running_ = false; |
+} |
+ |
+::Window TestDragDropClient::FindWindowFor(const gfx::Point& screen_point) { |
+ return target_xid_; |
+} |
+ |
+void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) { |
+ std::map<::Window, ClientMessageEventCollector*>::iterator it = |
+ collectors_.find(xid); |
+ if (it != collectors_.end()) |
+ it->second->RecordEvent(event->xclient); |
+} |
+ |
+} // namespace |
+ |
+class DesktopDragDropClientAuraX11Test : public ViewsTestBase { |
+ public: |
+ DesktopDragDropClientAuraX11Test() { |
+ } |
+ |
+ virtual ~DesktopDragDropClientAuraX11Test() { |
+ } |
+ |
+ int StartDragAndDrop() { |
+ ui::OSExchangeData data; |
+ data.SetString(base::ASCIIToUTF16("Test")); |
+ |
+ return client_->StartDragAndDrop( |
+ data, |
+ widget_->GetNativeWindow()->GetRootWindow(), |
+ widget_->GetNativeWindow(), |
+ gfx::Point(), |
+ ui::DragDropTypes::DRAG_COPY, |
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); |
+ } |
+ |
+ // ViewsTestBase: |
+ virtual void SetUp() OVERRIDE { |
+ ViewsTestBase::SetUp(); |
+ |
+ // Create widget to initiate the drags. |
+ widget_.reset(new Widget); |
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); |
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
+ params.native_widget = new DesktopNativeWidgetAura(widget_.get()); |
+ params.bounds = gfx::Rect(100, 100); |
+ widget_->Init(params); |
+ widget_->Show(); |
+ |
+ cursor_manager_.reset(new DesktopNativeCursorManager( |
+ DesktopCursorLoaderUpdater::Create())); |
+ |
+ client_.reset(new TestDragDropClient(widget_->GetNativeWindow(), |
+ cursor_manager_.get())); |
+ } |
+ |
+ virtual void TearDown() OVERRIDE { |
+ client_.reset(); |
+ cursor_manager_.reset(); |
+ widget_.reset(); |
+ ViewsTestBase::TearDown(); |
+ } |
+ |
+ TestDragDropClient* client() { |
+ return client_.get(); |
+ } |
+ |
+ private: |
+ scoped_ptr<TestDragDropClient> client_; |
+ scoped_ptr<DesktopNativeCursorManager> cursor_manager_; |
+ |
+ // The widget used to initiate drags. |
+ scoped_ptr<Widget> widget_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test); |
+}; |
+ |
+namespace { |
+ |
+void BasicStep2(TestDragDropClient* client, XID toplevel) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ // XdndEnter should have been sent to |toplevel| before the XdndPosition |
+ // message. |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_EQ(client->source_xwindow(), |
+ static_cast<XID>(events[0].data.l[0])); |
+ EXPECT_EQ(1, events[0].data.l[1] & 1); |
+ std::vector<Atom> targets; |
+ ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets); |
+ EXPECT_FALSE(targets.empty()); |
+ |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ EXPECT_EQ(client->source_xwindow(), |
+ static_cast<XID>(events[0].data.l[0])); |
+ const long kCoords = |
+ TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY; |
+ EXPECT_EQ(kCoords, events[1].data.l[2]); |
+ EXPECT_EQ(client->GetAtom("XdndActionCopy"), |
+ static_cast<Atom>(events[1].data.l[4])); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ |
+ // Because there is no unprocessed XdndPosition, the drag drop client should |
+ // send XdndDrop immediately after the mouse is released. |
+ client->OnMouseReleased(); |
+ |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop")); |
+ EXPECT_EQ(client->source_xwindow(), |
+ static_cast<XID>(events[0].data.l[0])); |
+ |
+ // Send XdndFinished to indicate that the drag drop client can cleanup any |
+ // data related to this drag. The move loop should end only after the |
+ // XdndFinished message was received. |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+void BasicStep3(TestDragDropClient* client, XID toplevel) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition")); |
+ |
+ // We have not received an XdndStatus ack for the second XdndPosition message. |
+ // Test that sending XdndDrop is delayed till the XdndStatus ack is received. |
+ client->OnMouseReleased(); |
+ EXPECT_FALSE(collector.HasEvents()); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop")); |
+ |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+} // namespace |
+ |
+TEST_F(DesktopDragDropClientAuraX11Test, Basic) { |
+ XID toplevel = 1; |
+ |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(&BasicStep2, |
+ client(), |
+ toplevel)); |
+ int result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result); |
+ |
+ // Do another drag and drop to test that the data is properly cleaned up as a |
+ // result of the XdndFinished message. |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(&BasicStep3, |
+ client(), |
+ toplevel)); |
+ result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result); |
+} |
+ |
+namespace { |
+ |
+void TargetDoesNotRespondStep2(TestDragDropClient* client) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ XID toplevel = 1; |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ |
+ client->OnMouseReleased(); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+} // namespace |
+ |
+// Test that we do not wait for the target to send XdndStatus if we have not |
+// received any XdndStatus messages at all from the target. The Unity |
+// DNDCollectionWindow is an example of an XdndAware target which does not |
+// respond to XdndPosition messages at all. |
+TEST_F(DesktopDragDropClientAuraX11Test, TargetDoesNotRespond) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&TargetDoesNotRespondStep2, client())); |
+ int result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result); |
+} |
+ |
+namespace { |
+ |
+void QueuePositionStep2(TestDragDropClient* client) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ XID toplevel = 1; |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(collector.HasEvents()); |
+ |
+ client->OnMouseReleased(); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDropped")); |
+ |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+} // namespace |
+ |
+// Test that XdndPosition messages are queued till the pending XdndPosition |
+// message is acked via an XdndStatus message. |
+TEST_F(DesktopDragDropClientAuraX11Test, QueuePosition) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&QueuePositionStep2, client())); |
+ int result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result); |
+} |
+ |
+namespace { |
+ |
+void TargetChangesStep2(TestDragDropClient* client) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ XID toplevel1 = 1; |
+ ClientMessageEventCollector collector1(toplevel1, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel1); |
+ |
+ std::vector<XClientMessageEvent> events1 = collector1.PopAllEvents(); |
+ ASSERT_EQ(2u, events1.size()); |
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition")); |
+ |
+ XID toplevel2 = 2; |
+ ClientMessageEventCollector collector2(toplevel2, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel2); |
+ |
+ // It is possible for |toplevel1| to send XdndStatus after the source has sent |
+ // XdndLeave but before |toplevel1| has received the XdndLeave message. The |
+ // XdndStatus message should be ignored. |
+ client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy")); |
+ events1 = collector1.PopAllEvents(); |
+ ASSERT_EQ(1u, events1.size()); |
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave")); |
+ |
+ 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
|
+ ASSERT_EQ(2u, events2.size()); |
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy")); |
+ client->OnMouseReleased(); |
+ events2 = collector2.PopAllEvents(); |
+ ASSERT_EQ(1u, events2.size()); |
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop")); |
+ |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+} // namespace |
+ |
+// Test the behavior when the target changes during a drag. |
+TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&TargetChangesStep2, client())); |
+ int result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result); |
+} |
+ |
+namespace { |
+ |
+void RejectAfterMouseReleaseStep2(TestDragDropClient* client) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ XID toplevel = 1; |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(collector.HasEvents()); |
+ |
+ // Send another mouse move such that there is a pending XdndPosition. |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition")); |
+ |
+ client->OnMouseReleased(); |
+ // Reject the drop. |
+ client->OnStatus(toplevel, false, None); |
+ |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave")); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+void RejectAfterMouseReleaseStep3(TestDragDropClient* client) { |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ |
+ XID toplevel = 2; |
+ ClientMessageEventCollector collector(toplevel, client); |
+ client->SetTopmostXWindowAndMoveMouse(toplevel); |
+ |
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents(); |
+ ASSERT_EQ(2u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter")); |
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition")); |
+ |
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy")); |
+ EXPECT_FALSE(collector.HasEvents()); |
+ |
+ client->OnMouseReleased(); |
+ events = collector.PopAllEvents(); |
+ ASSERT_EQ(1u, events.size()); |
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop")); |
+ |
+ EXPECT_TRUE(client->IsMoveLoopRunning()); |
+ client->OnFinished(toplevel, false, None); |
+ EXPECT_FALSE(client->IsMoveLoopRunning()); |
+} |
+ |
+} // namespace |
+ |
+// Test that the source sends XdndLeave instead of XdndDrop if the drag |
+// operation is rejected after the mouse is released. |
+TEST_F(DesktopDragDropClientAuraX11Test, RejectAfterMouseRelease) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RejectAfterMouseReleaseStep2, client())); |
+ int result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result); |
+ |
+ // Repeat the test but reject the drop in the XdndFinished message instead. |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RejectAfterMouseReleaseStep3, client())); |
+ result = StartDragAndDrop(); |
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result); |
+} |
+ |
+} // namespace views |