// Copyright 2018 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 "services/ws/drag_drop_delegate.h" #include "base/bind.h" #include "base/strings/string16.h" #include "mojo/public/cpp/bindings/map.h" #include "ui/aura/mus/os_exchange_data_provider_mus.h" #include "ui/base/dragdrop/drop_target_event.h" #include "ui/base/dragdrop/file_info.h" #include "ui/gfx/geometry/point.h" #include "ui/wm/core/coordinate_conversion.h" #include "url/gurl.h" namespace ws { namespace { // Converts OSExchangeData into mime type data. using DragDataType = aura::OSExchangeDataProviderMus::Data; DragDataType GetDragData(const ui::OSExchangeData& data) { aura::OSExchangeDataProviderMus mus_provider; base::string16 string; if (data.GetString(&string)) mus_provider.SetString(string); GURL url; base::string16 title; if (data.GetURLAndTitle(ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES, &url, &title)) { mus_provider.SetURL(url, title); } std::vector file_names; if (data.GetFilenames(&file_names)) mus_provider.SetFilenames(file_names); base::string16 html; GURL base_url; if (data.GetHtml(&html, &base_url)) mus_provider.SetHtml(html, base_url); return mus_provider.GetData(); } // Converts |location| in |window| coordinates to screen coordinates. gfx::Point ToScreenLocation(aura::Window* window, const gfx::Point& location) { gfx::Point screen_location(location); wm::ConvertPointToScreen(window, &screen_location); return screen_location; } } // namespace DragDropDelegate::DragDropDelegate(mojom::WindowTreeClient* window_tree_client, aura::Window* window, Id transport_window_id) : tree_client_(window_tree_client), window_(window), transport_window_id_(transport_window_id) {} DragDropDelegate::~DragDropDelegate() { if (in_drag_) EndDrag(); } void DragDropDelegate::OnDragEntered(const ui::DropTargetEvent& event) { StartDrag(event); tree_client_->OnDragEnter( transport_window_id_, event.flags(), ToScreenLocation(window_, event.location()), event.source_operations(), base::BindOnce(&DragDropDelegate::UpdateDragOperations, weak_ptr_factory_.GetWeakPtr())); } int DragDropDelegate::OnDragUpdated(const ui::DropTargetEvent& event) { DCHECK(in_drag_); tree_client_->OnDragOver( transport_window_id_, event.flags(), ToScreenLocation(window_, event.location()), event.source_operations(), base::BindOnce(&DragDropDelegate::UpdateDragOperations, weak_ptr_factory_.GetWeakPtr())); return last_drag_operations_; } void DragDropDelegate::OnDragExited() { DCHECK(in_drag_); tree_client_->OnDragLeave(transport_window_id_); EndDrag(); } int DragDropDelegate::OnPerformDrop(const ui::DropTargetEvent& event) { DCHECK(in_drag_); tree_client_->OnCompleteDrop(transport_window_id_, event.flags(), ToScreenLocation(window_, event.location()), event.source_operations(), base::DoNothing()); EndDrag(); // Returns a drop action derived from |last_drag_operations_| because it is // not safe to hold the stack and wait for the mojo to return the actual one. if (last_drag_operations_ == ui::DragDropTypes::DRAG_NONE) return ui::DragDropTypes::DRAG_NONE; return (last_drag_operations_ & ui::DragDropTypes::DRAG_MOVE) ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; } void DragDropDelegate::StartDrag(const ui::DropTargetEvent& event) { DCHECK(!in_drag_); in_drag_ = true; tree_client_->OnDragDropStart(mojo::MapToFlatMap(GetDragData(event.data()))); } void DragDropDelegate::EndDrag() { DCHECK(in_drag_); in_drag_ = false; tree_client_->OnDragDropDone(); } void DragDropDelegate::UpdateDragOperations(uint32_t drag_operations) { last_drag_operations_ = drag_operations; } } // namespace ws