diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc index 5f01b59b04ef50..184b7df4962a87 100644 --- a/ash/drag_drop/drag_drop_controller.cc +++ b/ash/drag_drop/drag_drop_controller.cc @@ -619,15 +619,19 @@ void DragDropController::Drop(aura::Window* target, aura::client::GetDragDropDelegate(target); aura::client::DragDropDelegate::DropCallback delegate_drop_cb = - base::DoNothing(); + base::NullCallback(); + aura::client::DragDropDelegate::DropCallbackWithAnimation + delegate_drop_cb_animation = base::NullCallback(); ui::DropTargetEvent e(*drag_data_.get(), event.location_f(), event.root_location_f(), allowed_operations_); e.set_flags(event.flags()); ui::Event::DispatcherApi(&e).set_target(target); - if (delegate) + if (delegate) { + delegate_drop_cb_animation = delegate->GetDropCallbackWithAnimation(e); delegate_drop_cb = delegate->GetDropCallback(e); + } base::ScopedClosureRunner drag_cancel(base::BindOnce( &DragDropController::DragCancel, weak_factory_.GetWeakPtr())); @@ -642,11 +646,11 @@ void DragDropController::Drop(aura::Window* target, DropIfAllowed( drag_data_.get(), current_drag_info_, - base::BindOnce(&DragDropController::PerformDrop, - weak_factory_.GetWeakPtr(), drop_location_in_screen, e, - std::move(drag_data_), std::move(delegate_drop_cb), - std::move(tab_drag_drop_delegate_), - std::move(drag_cancel))); + base::BindOnce( + &DragDropController::PerformDrop, weak_factory_.GetWeakPtr(), + drop_location_in_screen, e, std::move(drag_data_), + std::move(delegate_drop_cb), std::move(delegate_drop_cb_animation), + std::move(tab_drag_drop_delegate_), std::move(drag_cancel))); // During the drop, the event target (or its ancestors) might have // been destroyed, eg by the client reaction. Adapt the DropTargetEvent @@ -820,6 +824,7 @@ void DragDropController::PerformDrop( ui::DropTargetEvent event, std::unique_ptr drag_data, aura::client::DragDropDelegate::DropCallback drop_cb, + aura::client::DragDropDelegate::DropCallbackWithAnimation drop_cb_animation, std::unique_ptr tab_drag_drop_delegate, base::ScopedClosureRunner drag_cancel) { // Event copy constructor dooesn't copy the target. That's why we set it here. @@ -828,7 +833,11 @@ void DragDropController::PerformDrop( ui::Event::DispatcherApi(&event).set_target(drag_window_); ui::OSExchangeData copied_data(drag_data->provider().Clone()); - if (drop_cb) { + if (!!drop_cb_animation) { + std::move(drop_cb_animation) + .Run(std::move(drag_data), operation_, + ::wm::RecreateLayers(drag_image_widget_->GetNativeWindow())); + } else if (!!drop_cb) { std::move(drop_cb).Run(std::move(drag_data), operation_); } diff --git a/ash/drag_drop/drag_drop_controller.h b/ash/drag_drop/drag_drop_controller.h index 78dc38f46413c8..0be258cc49ef33 100644 --- a/ash/drag_drop/drag_drop_controller.h +++ b/ash/drag_drop/drag_drop_controller.h @@ -166,6 +166,8 @@ class ASH_EXPORT DragDropController : public aura::client::DragDropClient, ui::DropTargetEvent event, std::unique_ptr drag_data, aura::client::DragDropDelegate::DropCallback drop_cb, + aura::client::DragDropDelegate::DropCallbackWithAnimation + drop_cb_animation, std::unique_ptr tab_drag_drop_delegate, base::ScopedClosureRunner drag_cancel); @@ -173,7 +175,7 @@ class ASH_EXPORT DragDropController : public aura::client::DragDropClient, bool enabled_ = false; bool drag_drop_completed_ = true; - views::UniqueWidgetPtr drag_image_widget_; + std::unique_ptr drag_image_widget_; gfx::Vector2d drag_image_offset_; std::unique_ptr drag_data_; int allowed_operations_ = 0; diff --git a/ash/drag_drop/drag_image_view.cc b/ash/drag_drop/drag_image_view.cc index 4475ed1e2d2d12..1d80b706e2fbe2 100644 --- a/ash/drag_drop/drag_image_view.cc +++ b/ash/drag_drop/drag_image_view.cc @@ -28,7 +28,7 @@ DragImageView::DragImageView(ui::mojom::DragEventSource event_source) DragImageView::~DragImageView() = default; // static -views::UniqueWidgetPtr DragImageView::Create( +std::unique_ptr DragImageView::Create( aura::Window* root_window, ui::mojom::DragEventSource event_source) { views::Widget::InitParams params; @@ -37,12 +37,12 @@ views::UniqueWidgetPtr DragImageView::Create( params.accept_events = false; params.shadow_type = views::Widget::InitParams::ShadowType::kNone; params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.parent = root_window->GetChildById(kShellWindowId_DragImageAndTooltipContainer); if (!params.parent) params.context = root_window; // Happens in tests. - auto drag_widget = views::UniqueWidgetPtr( - std::make_unique(std::move(params))); + auto drag_widget = std::make_unique(std::move(params)); drag_widget->SetOpacity(1.f); drag_widget->SetContentsView( base::WrapUnique(new DragImageView(event_source))); diff --git a/ash/drag_drop/drag_image_view.h b/ash/drag_drop/drag_image_view.h index 2fb79aaef660e4..d39817ca26cbe7 100644 --- a/ash/drag_drop/drag_image_view.h +++ b/ash/drag_drop/drag_image_view.h @@ -11,7 +11,6 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/views/controls/image_view.h" -#include "ui/views/widget/unique_widget_ptr.h" namespace aura { class Window; @@ -38,8 +37,9 @@ class ASH_EXPORT DragImageView : public views::ImageView { // |source| is the event source that started this drag drop operation (touch // or mouse). It is used to determine attributes of the drag image such as // whether to show drag operation hint on top of the image. - static views::UniqueWidgetPtr Create(aura::Window* root_window, - ui::mojom::DragEventSource source); + static std::unique_ptr Create( + aura::Window* root_window, + ui::mojom::DragEventSource source); // Sets the bounds of the native widget in screen // coordinates. diff --git a/ui/aura/client/drag_drop_delegate.cc b/ui/aura/client/drag_drop_delegate.cc index 649ff3e090faa5..a5e0cb53b197d5 100644 --- a/ui/aura/client/drag_drop_delegate.cc +++ b/ui/aura/client/drag_drop_delegate.cc @@ -25,6 +25,12 @@ DragUpdateInfo& DragUpdateInfo::operator=(const DragUpdateInfo& update_info) = DEFINE_UI_CLASS_PROPERTY_KEY(DragDropDelegate*, kDragDropDelegateKey, nullptr) +DragDropDelegate::DropCallbackWithAnimation +DragDropDelegate::GetDropCallbackWithAnimation( + const ui::DropTargetEvent& event) { + return base::NullCallback(); +} + void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) { window->SetProperty(kDragDropDelegateKey, delegate); } diff --git a/ui/aura/client/drag_drop_delegate.h b/ui/aura/client/drag_drop_delegate.h index eed95e4a71ed6a..d0e5631053c556 100644 --- a/ui/aura/client/drag_drop_delegate.h +++ b/ui/aura/client/drag_drop_delegate.h @@ -17,7 +17,8 @@ namespace ui { class DropTargetEvent; -} +class LayerTreeOwner; +} // namespace ui namespace aura { class Window; @@ -46,6 +47,13 @@ class AURA_EXPORT DragDropDelegate { base::OnceCallback data, ui::mojom::DragOperation& output_drag_op)>; + // Callback emitted by GetDropCallbackWithAnimation used to handle deferred + // drop events and drag image dropping animation. + using DropCallbackWithAnimation = base::OnceCallback data, + ui::mojom::DragOperation& output_drag_op, + std::unique_ptr old_layer_owner)>; + // OnDragEntered is invoked when the mouse enters this window during a drag & // drop session. This is immediately followed by an invocation of // OnDragUpdated, and eventually one of OnDragExited, or GetDropCallback. @@ -62,9 +70,14 @@ class AURA_EXPORT DragDropDelegate { // Invoked during a drag and drop session when the user release the mouse, but // the drop is held because of the DataTransferPolicyController. - // The returned callback may be NullCallback if there's nothing to do and the - // drop event is ignored. + // The implementation may support different a callback to obtain a drag image + // widget and manipulate the dropping animation when + // GetDropCallbackWithAnimation returns base::NullCallback(). Otherwise, the + // implementation will fallback to the default GetDropCallback(). If both + // callbacks are null, there's nothing to do and the drop event is ignored. virtual DropCallback GetDropCallback(const ui::DropTargetEvent& event) = 0; + virtual DropCallbackWithAnimation GetDropCallbackWithAnimation( + const ui::DropTargetEvent& event); protected: virtual ~DragDropDelegate() {} diff --git a/ui/views/view.cc b/ui/views/view.cc index 30dbd9abf515ff..6598da412ffacd 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc @@ -1877,6 +1877,11 @@ View::DropCallback View::GetDropCallback(const ui::DropTargetEvent& event) { return base::NullCallback(); } +View::DropCallbackWithAnimation View::GetDropCallbackWithAnimation( + const ui::DropTargetEvent& event) { + return base::NullCallback(); +} + // static bool View::ExceededDragThreshold(const gfx::Vector2d& delta) { return (abs(delta.x()) > GetHorizontalDragThreshold() || diff --git a/ui/views/view.h b/ui/views/view.h index 93a815e296c1ca..1229081f79bab3 100644 --- a/ui/views/view.h +++ b/ui/views/view.h @@ -70,6 +70,7 @@ class ColorProvider; class Compositor; class InputMethod; class Layer; +class LayerTreeOwner; class NativeTheme; class PaintContext; class ThemeProvider; @@ -295,6 +296,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, base::OnceCallback; + using DropCallbackWithAnimation = base::OnceCallback old_layer_owner)>; + METADATA_HEADER_BASE(View); enum class FocusBehavior { @@ -1411,6 +1417,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // uses View local coordinates. virtual DropCallback GetDropCallback(const ui::DropTargetEvent& event); + // Invoked during a drag and drop session when the user release the mouse. + // Similar to GetDropCallback() but the returned callback has access to the + // drag image layer if any animation is needed. + virtual DropCallbackWithAnimation GetDropCallbackWithAnimation( + const ui::DropTargetEvent& event); + // Returns true if the mouse was dragged enough to start a drag operation. // delta_x and y are the distance the mouse was dragged. static bool ExceededDragThreshold(const gfx::Vector2d& delta); diff --git a/ui/views/widget/drop_helper.cc b/ui/views/widget/drop_helper.cc index 70b46a693eaa4e..17382ddaacaa85 100644 --- a/ui/views/widget/drop_helper.cc +++ b/ui/views/widget/drop_helper.cc @@ -15,6 +15,7 @@ #include "build/build_config.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" +#include "ui/compositor/layer_tree_owner.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -143,6 +144,51 @@ DropHelper::DropCallback DropHelper::GetDropCallback( drop_event, std::move(drop_view_cb)); } +DropHelper::DropCallbackWithAnimation DropHelper::GetDropCallbackWithAnimation( + const OSExchangeData& data, + const gfx::Point& root_view_location, + int drag_operation) { + View* drop_view = target_view_; + if (!drop_view) { + return base::NullCallback(); + } + + if (drag_operation == ui::DragDropTypes::DRAG_NONE) { + drop_view->OnDragExited(); + return base::NullCallback(); + } + + gfx::Point view_location(root_view_location); + View* root_view = drop_view->GetWidget()->GetRootView(); + View::ConvertPointToTarget(root_view, drop_view, &view_location); + ui::DropTargetEvent drop_event(data, gfx::PointF(view_location), + gfx::PointF(view_location), drag_operation); + + auto drop_view_cb = drop_view->GetDropCallbackWithAnimation(drop_event); + if (!drop_view_cb) { + return base::NullCallback(); + } + + // Only reset the target view when the helper successfully returns a callback. + // If no callback is returned here, GetDropCallback might still need the + // target view. + deepest_view_ = target_view_ = nullptr; + + return base::BindOnce( + [](const ui::DropTargetEvent& drop_event, + View::DropCallbackWithAnimation drop_cb, + std::unique_ptr data, + ui::mojom::DragOperation& output_drag_op, + std::unique_ptr old_layer_owner) { + // Bind the drop_event here instead of using the one that the callback + // is invoked with as that event is in window coordinates and callbacks + // expect View coordinates. + std::move(drop_cb).Run(drop_event, output_drag_op, + std::move(old_layer_owner)); + }, + drop_event, std::move(drop_view_cb)); +} + View* DropHelper::CalculateTargetView(const gfx::Point& root_view_location, const OSExchangeData& data, bool check_can_drop) { diff --git a/ui/views/widget/drop_helper.h b/ui/views/widget/drop_helper.h index ceabf8a48ca3bd..6ba37860c8fe57 100644 --- a/ui/views/widget/drop_helper.h +++ b/ui/views/widget/drop_helper.h @@ -39,6 +39,13 @@ class VIEWS_EXPORT DropHelper { base::OnceCallback data, ui::mojom::DragOperation& output_drag_op)>; + // This is expected to match the signature of + // aura::client::DragDropDelegate::DropCallbackWithAnimation. + using DropCallbackWithAnimation = base::OnceCallback data, + ui::mojom::DragOperation& output_drag_op, + std::unique_ptr old_layer_owner)>; + explicit DropHelper(View* root_view); DropHelper(const DropHelper&) = delete; @@ -85,9 +92,18 @@ class VIEWS_EXPORT DropHelper { // Invoked when the user drops data on the root view during a drag and drop // operation, but the drop is held because of DataTransferPolicController. + // To fetch the correct callback, callers should invoke + // GetDropCallbackWithAnimation before GetDropCallback to potentially avoid + // clearing the |target_view_| in case GetDropCallback should need it. DropCallback GetDropCallback(const OSExchangeData& data, const gfx::Point& root_view_location, int drag_operation); + DropCallbackWithAnimation GetDropCallbackWithAnimation( + const OSExchangeData& data, + const gfx::Point& root_view_location, + int drag_operation); + + bool WillAnimateDragImageForDrop(); // Calculates the target view for a drop given the specified location in // the coordinate system of the rootview. This tries to avoid continually diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index f1949d4eca1eed..5703b0e0f77453 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -1199,6 +1199,14 @@ aura::client::DragDropDelegate::DropCallback NativeWidgetAura::GetDropCallback( last_drop_operation_); } +aura::client::DragDropDelegate::DropCallbackWithAnimation +NativeWidgetAura::GetDropCallbackWithAnimation( + const ui::DropTargetEvent& event) { + DCHECK(drop_helper_); + return drop_helper_->GetDropCallbackWithAnimation( + event.data(), event.location(), last_drop_operation_); +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetAura, wm::TransientWindowObserver implementation: diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h index 5fcf32da805a92..67f90557ddd7a6 100644 --- a/ui/views/widget/native_widget_aura.h +++ b/ui/views/widget/native_widget_aura.h @@ -228,6 +228,8 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, void OnDragExited() override; aura::client::DragDropDelegate::DropCallback GetDropCallback( const ui::DropTargetEvent& event) override; + aura::client::DragDropDelegate::DropCallbackWithAnimation + GetDropCallbackWithAnimation(const ui::DropTargetEvent& event) override; // aura::TransientWindowObserver: void OnTransientParentChanged(aura::Window* new_parent) override;