| // Copyright 2020 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 UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_ |
| #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_ |
| |
| #include <cstdint> |
| #include <iosfwd> |
| #include <memory> |
| #include <string> |
| |
| #include "base/callback_forward.h" |
| #include "base/memory/weak_ptr.h" |
| #include "ui/events/event.h" |
| #include "ui/events/platform/platform_event_dispatcher.h" |
| #include "ui/events/platform/scoped_event_dispatcher.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/ozone/platform/wayland/common/wayland_object.h" |
| #include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h" |
| #include "ui/ozone/platform/wayland/host/wayland_data_device.h" |
| #include "ui/ozone/platform/wayland/host/wayland_data_source.h" |
| #include "ui/ozone/platform/wayland/host/wayland_pointer.h" |
| #include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h" |
| #include "ui/ozone/platform/wayland/host/wayland_touch.h" |
| #include "ui/ozone/platform/wayland/host/wayland_window_observer.h" |
| |
| namespace ui { |
| |
| class WaylandConnection; |
| class WaylandDataDeviceManager; |
| class WaylandDataOffer; |
| class WaylandWindow; |
| class WaylandWindowManager; |
| class WaylandSurface; |
| |
| // Drag controller implementation that drives window moving sessions (aka: tab |
| // dragging). Wayland Drag and Drop protocol is used, under the hood, to keep |
| // track of cursor location and surface focus. |
| // |
| // TODO(crbug.com/896640): Use drag icon to emulate window moving. |
| class WaylandWindowDragController : public WaylandDataDevice::DragDelegate, |
| public WaylandDataSource::Delegate, |
| public PlatformEventDispatcher, |
| public WaylandWindowObserver { |
| public: |
| // Constants used to keep track of the drag controller state. |
| enum class State { |
| kIdle, // No DnD session nor drag loop running. |
| kAttached, // DnD session ongoing but no drag loop running. |
| kDetached, // Drag loop running. ie: blocked in a Drag() call. |
| kDropped, // Drop event was just received. |
| kAttaching, // About to transition back to |kAttached|. |
| }; |
| enum class DragSource { |
| kMouse, |
| kTouch, |
| }; |
| |
| WaylandWindowDragController(WaylandConnection* connection, |
| WaylandDataDeviceManager* device_manager, |
| WaylandPointer::Delegate* pointer_delegate, |
| WaylandTouch::Delegate* touch_delegate); |
| WaylandWindowDragController(const WaylandWindowDragController&) = delete; |
| WaylandWindowDragController& operator=(const WaylandWindowDragController&) = |
| delete; |
| ~WaylandWindowDragController() override; |
| |
| // Starts a new Wayland DND session for window dragging, if not done yet. A |
| // new data source is setup and the focused window is used as the origin |
| // surface. |
| bool StartDragSession(); |
| |
| bool Drag(WaylandToplevelWindow* window, const gfx::Vector2d& offset); |
| void StopDragging(); |
| |
| State state() const { return state_; } |
| |
| void OnToplevelWindowCreated(WaylandToplevelWindow* window); |
| |
| private: |
| class ExtendedDragSource; |
| |
| // WaylandDataDevice::DragDelegate: |
| bool IsDragSource() const override; |
| void DrawIcon() override; |
| void OnDragOffer(std::unique_ptr<WaylandDataOffer> offer) override; |
| void OnDragEnter(WaylandWindow* window, |
| const gfx::PointF& location, |
| uint32_t serial) override; |
| void OnDragMotion(const gfx::PointF& location) override; |
| void OnDragLeave() override; |
| void OnDragDrop() override; |
| |
| // WaylandDataSource::Delegate |
| void OnDataSourceFinish(bool completed) override; |
| void OnDataSourceSend(const std::string& mime_type, |
| std::string* contents) override; |
| |
| // PlatformEventDispatcher |
| bool CanDispatchEvent(const PlatformEvent& event) override; |
| uint32_t DispatchEvent(const PlatformEvent& event) override; |
| |
| // WaylandWindowObserver: |
| void OnWindowRemoved(WaylandWindow* window) override; |
| |
| // Handles drag/move mouse |event|, while in |kDetached| mode, forwarding it |
| // as a bounds change event to the upper layer handlers. |
| void HandleMotionEvent(LocatedEvent* event); |
| // Handles the mouse button release (i.e: drop). Dispatches the required |
| // events and resets the internal state. |
| void HandleDropAndResetState(); |
| // Registers as the top level PlatformEvent dispatcher and runs a nested |
| // RunLoop, which blocks until the DnD session finishes. |
| void RunLoop(); |
| // Unregisters the internal event dispatcher and asks to quit the nested loop. |
| void QuitLoop(); |
| // Set |window| as the current dragged window and |offset| as the drag offset, |
| // which makes |window| to appear anchored to the pointer cursor, if |
| // extended-drag extension is available. |
| void SetDraggedWindow(WaylandToplevelWindow* window, |
| const gfx::Vector2d& offset); |
| // Tells if "extended drag" extension is available. |
| bool IsExtendedDragAvailable() const; |
| |
| WaylandConnection* const connection_; |
| WaylandDataDeviceManager* const data_device_manager_; |
| WaylandDataDevice* const data_device_; |
| WaylandWindowManager* const window_manager_; |
| WaylandPointer::Delegate* const pointer_delegate_; |
| WaylandTouch::Delegate* const touch_delegate_; |
| |
| State state_ = State::kIdle; |
| absl::optional<DragSource> drag_source_; |
| |
| gfx::Vector2d drag_offset_; |
| |
| // The last known pointer location in DIP. |
| gfx::PointF pointer_location_; |
| |
| std::unique_ptr<WaylandDataSource> data_source_; |
| std::unique_ptr<WaylandDataOffer> data_offer_; |
| |
| std::unique_ptr<ExtendedDragSource> extended_drag_source_; |
| |
| // The current toplevel window being dragged, when in detached mode. |
| WaylandToplevelWindow* dragged_window_ = nullptr; |
| |
| // Keeps track of the window that holds the pointer grab. i.e: the owner of |
| // the surface that must receive the mouse release event upon drop. |
| WaylandWindow* pointer_grab_owner_ = nullptr; |
| |
| // The window where the DND session originated from. i.e: which had the |
| // pointer focus when the session was initiated. |
| WaylandWindow* origin_window_ = nullptr; |
| |
| // The |origin_window_| can be destroyed during the DND session. If this |
| // happens, |origin_surface_| takes ownership of its surface and ensure it |
| // is kept alive until the end of the session. |
| std::unique_ptr<WaylandSurface> origin_surface_; |
| |
| std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_; |
| base::OnceClosure quit_loop_closure_; |
| |
| // Tells if the current drag event should be processed. Buggy compositors may |
| // send wl_pointer::motion events, for example, while a DND session is still |
| // in progress, which leads to issues in window dragging sessions, this flag |
| // is used to make window drag controller resistant to such scenarios. |
| bool should_process_drag_event_ = false; |
| |
| base::WeakPtrFactory<WaylandWindowDragController> weak_factory_{this}; |
| }; |
| |
| // Stream operator so WaylandWindowDragController::State can be used in |
| // log/assertion statements. |
| std::ostream& operator<<(std::ostream& out, |
| WaylandWindowDragController::State state); |
| |
| } // namespace ui |
| |
| #endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_ |