#ifndef ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_
#define ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_
#include <memory>
#include "ash/ash_export.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/drag_drop/drag_drop_capture_delegate.h"
#include "ash/drag_drop/tab_drag_drop_delegate.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window_observer.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/widget/unique_widget_ptr.h"
namespace gfx {
class LinearAnimation;
}
namespace ui {
class LocatedEvent;
}
namespace ash {
class ToplevelWindowDragDelegate;
class ASH_EXPORT DragDropController : public aura::client::DragDropClient,
public ui::EventHandler,
public gfx::AnimationDelegate,
public aura::WindowObserver,
public WindowTreeHostManager::Observer {
public:
DragDropController();
DragDropController(const DragDropController&) = delete;
DragDropController& operator=(const DragDropController&) = delete;
~DragDropController() override;
void set_enabled(bool enabled) { enabled_ = enabled; }
void set_toplevel_window_drag_delegate(ToplevelWindowDragDelegate* delegate) {
toplevel_window_drag_delegate_ = delegate;
}
bool IsDragDropCompleted();
ui::mojom::DragOperation StartDragAndDrop(
std::unique_ptr<ui::OSExchangeData> data,
aura::Window* root_window,
aura::Window* source_window,
const gfx::Point& screen_location,
int allowed_operations,
ui::mojom::DragEventSource source) override;
void DragCancel() override;
bool IsDragDropInProgress() override;
void AddObserver(aura::client::DragDropClientObserver* observer) override;
void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
void OnWindowDestroying(aura::Window* window) override;
void SetDragImage(const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset);
ui::mojom::DragEventSource event_source() {
return current_drag_event_source_;
}
using TestLoopClosure = base::RepeatingCallback<void()>;
void SetLoopClosureForTesting(TestLoopClosure closure,
base::OnceClosure quit_closure);
void SetDisableNestedLoopForTesting(bool disable);
void set_should_block_during_drag_drop(bool should_block_during_drag_drop) {
SetDisableNestedLoopForTesting(!should_block_during_drag_drop);
}
protected:
virtual gfx::LinearAnimation* CreateCancelAnimation(
base::TimeDelta duration,
int frame_rate,
gfx::AnimationDelegate* delegate);
virtual void DragUpdate(aura::Window* target, const ui::LocatedEvent& event);
virtual void Drop(aura::Window* target, const ui::LocatedEvent& event);
virtual void DoDragCancel(base::TimeDelta drag_cancel_animation_duration);
DragDropCaptureDelegate* get_capture_delegate() { return capture_delegate_; }
private:
friend class DragDropControllerTest;
friend class DragDropControllerTestApi;
void AnimationEnded(const gfx::Animation* animation) override;
void AnimationProgressed(const gfx::Animation* animation) override;
void AnimationCanceled(const gfx::Animation* animation) override;
void OnDisplayConfigurationChanging() override;
void StartCanceledAnimation(base::TimeDelta animation_duration);
void ScheduleForwardPendingLongTap();
void ForwardPendingLongTap();
void Cleanup();
void CleanupPendingLongTap();
void PerformDrop(const gfx::Point drop_location_in_screen,
ui::DropTargetEvent event,
std::unique_ptr<ui::OSExchangeData> drag_data,
aura::client::DragDropDelegate::DropCallback drop_cb,
std::unique_ptr<TabDragDropDelegate> tab_drag_drop_delegate,
base::ScopedClosureRunner cancel_drag_callback);
void CancelIfInProgress();
bool enabled_ = false;
bool drag_drop_completed_ = true;
std::unique_ptr<views::Widget> drag_image_widget_;
gfx::Vector2d drag_image_offset_;
std::unique_ptr<ui::OSExchangeData> drag_data_;
int allowed_operations_ = 0;
ui::mojom::DragOperation operation_ = ui::mojom::DragOperation::kNone;
aura::client::DragUpdateInfo current_drag_info_;
std::unique_ptr<TabDragDropDelegate> tab_drag_drop_delegate_;
std::unique_ptr<DragDropCaptureDelegate> touch_drag_drop_delegate_;
raw_ptr<aura::Window, ExperimentalAsh> drag_window_ = nullptr;
gfx::Rect drag_image_initial_bounds_for_cancel_animation_;
gfx::Rect drag_image_final_bounds_for_cancel_animation_;
std::unique_ptr<gfx::LinearAnimation> cancel_animation_;
std::unique_ptr<gfx::AnimationDelegate> cancel_animation_notifier_;
raw_ptr<aura::Window, ExperimentalAsh> drag_source_window_ = nullptr;
TestLoopClosure test_loop_closure_;
bool nested_loop_disabled_for_testing_ = false;
base::OnceClosure quit_closure_;
raw_ptr<DragDropCaptureDelegate, ExperimentalAsh> capture_delegate_ = nullptr;
ui::mojom::DragEventSource current_drag_event_source_ =
ui::mojom::DragEventSource::kMouse;
std::unique_ptr<ui::Event> pending_long_tap_;
bool will_forward_long_tap_ = false;
gfx::Point start_location_;
gfx::Point current_location_;
base::ObserverList<aura::client::DragDropClientObserver>::Unchecked
observers_;
raw_ptr<ToplevelWindowDragDelegate, ExperimentalAsh>
toplevel_window_drag_delegate_ = nullptr;
base::WeakPtrFactory<DragDropController> weak_factory_{this};
};
}
#endif