// Copyright (c) 2012 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. #ifndef ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_ #define ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_ #include #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/callback.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; } // Overridden from aura::client::DragDropClient: ui::mojom::DragOperation StartDragAndDrop( std::unique_ptr 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; // Overridden from ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; void OnMouseEvent(ui::MouseEvent* event) override; void OnTouchEvent(ui::TouchEvent* event) override; void OnGestureEvent(ui::GestureEvent* event) override; // Overridden from aura::WindowObserver. 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_; } // Sets the `closure` that will be executed as a replacement of // inner event loop. A test can use this closure to generate events, or // take other actions that should happen during the drag and drop, and // can also check the condition that should be satisfied. // The loop closure is called with a boolean value that indicates // that this is called from the inner loop because the same closure will // often used to generate the event that will eventually enter the drag // and drop inner loop. The `quit_closure` is used for a test // to exit the outer loop in the test. using TestLoopClosure = base::RepeatingCallback; void SetLoopClosureForTesting(TestLoopClosure closure, base::OnceClosure quit_closure); void SetDisableNestedLoopForTesting(bool disable); // Deprecated: Use `SetDisableNestedLoopForTesting`. void set_should_block_during_drag_drop(bool should_block_during_drag_drop) { SetDisableNestedLoopForTesting(!should_block_during_drag_drop); } protected: // Helper method to create a LinearAnimation object that will run the drag // cancel animation. Caller take ownership of the returned object. Protected // for testing. virtual gfx::LinearAnimation* CreateCancelAnimation( base::TimeDelta duration, int frame_rate, gfx::AnimationDelegate* delegate); // Exposed for tests to override. virtual void DragUpdate(aura::Window* target, const ui::LocatedEvent& event); virtual void Drop(aura::Window* target, const ui::LocatedEvent& event); // Actual implementation of |DragCancel()|. protected for testing. virtual void DoDragCancel(base::TimeDelta drag_cancel_animation_duration); // Exposed for test assertions. DragDropCaptureDelegate* get_capture_delegate() { return capture_delegate_; } private: friend class DragDropControllerTest; friend class DragDropControllerTestApi; // Overridden from gfx::AnimationDelegate: void AnimationEnded(const gfx::Animation* animation) override; void AnimationProgressed(const gfx::Animation* animation) override; void AnimationCanceled(const gfx::Animation* animation) override; // WindowTreeHostManager::Observer: void OnDisplayConfigurationChanging() override; // Helper method to start drag widget flying back animation. void StartCanceledAnimation(base::TimeDelta animation_duration); // Helper methods to forward |pending_log_tap_| event to // |drag_source_window_|. void ScheduleForwardPendingLongTap(); void ForwardPendingLongTap(); // Helper method to reset most of the state, except state that could be used // during async operations of cancellation (including cancel animation and // posting task to dispatch long tap event). void Cleanup(); void CleanupPendingLongTap(); // Helper method to perform the drop if allowed by // DataTransferPolicyController. If it's run, `drag_cancel` will be replaced. // Otherwise `drag_cancel` will run to cancel the drag. void PerformDrop(const gfx::Point drop_location_in_screen, ui::DropTargetEvent event, std::unique_ptr drag_data, aura::client::DragDropDelegate::DropCallback drop_cb, std::unique_ptr tab_drag_drop_delegate, base::ScopedClosureRunner drag_cancel); void CancelIfInProgress(); bool enabled_ = false; views::UniqueWidgetPtr drag_image_widget_; gfx::Vector2d drag_image_offset_; std::unique_ptr drag_data_; int allowed_operations_ = 0; ui::mojom::DragOperation operation_ = ui::mojom::DragOperation::kNone; aura::client::DragUpdateInfo current_drag_info_; // Used when processing a Chrome tab drag from a WebUI tab strip. std::unique_ptr tab_drag_drop_delegate_; // Used when processing a normal drag and drop with touch. std::unique_ptr touch_drag_drop_delegate_; // Window that is currently under the drag cursor. aura::Window* drag_window_ = nullptr; // Starting and final bounds for the drag image for the drag cancel animation. gfx::Rect drag_image_initial_bounds_for_cancel_animation_; gfx::Rect drag_image_final_bounds_for_cancel_animation_; std::unique_ptr cancel_animation_; std::unique_ptr cancel_animation_notifier_; // Window that started the drag. aura::Window* drag_source_window_ = nullptr; // A closure that allows a test to implement the actions within // drag and drop event loop. TestLoopClosure test_loop_closure_; // True if the nested event loop is disabled. bool nested_loop_disabled_for_testing_ = false; // Closure for quitting nested run loop. base::OnceClosure quit_closure_; // If non-null, a drag is active which required a capture window. DragDropCaptureDelegate* capture_delegate_ = nullptr; ui::mojom::DragEventSource current_drag_event_source_ = ui::mojom::DragEventSource::kMouse; // Holds a synthetic long tap event to be sent to the |drag_source_window_|. // See comment in OnGestureEvent() on why we need this. std::unique_ptr pending_long_tap_; // Set to true during async operations of cancellation (including cancel // animation and posting task to dispatch long tap event), indicating that a // long tap event will be dispatched. bool will_forward_long_tap_ = false; gfx::Point start_location_; gfx::Point current_location_; base::ObserverList::Unchecked observers_; ToplevelWindowDragDelegate* toplevel_window_drag_delegate_ = nullptr; // Weak ptr for async callbacks to be invalidated if a new drag starts. base::WeakPtrFactory weak_factory_{this}; }; } // namespace ash #endif // ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_