Commit 83d5cd42 authored by Nick Diego Yamane's avatar Nick Diego Yamane Committed by Commit Bot

ozone/wayland: tabdrag: Start using zcr_extended_drag extension

Context: Wayland Protocol needed to be extended to make it possible to
properly support full Chromium's tab dragging experience. Further
details in the Design document [1].

This patch contains the first round of Wayland Ozone backend (client
side) changes needed to leverage the extended-drag protocol extension to
implement the remaining tab/window dragging missing features, whereas
the main one is the ability to set a toplevel shell surface (browser
window) as the "dragged surface", making it to be anchored to the
pointer cursor as it's dragged around, as well as being smoothly
droppable anywhere in the workspace, which is not possible with the
standard Wayland DND protocol.

[1] https://docs.google.com/document/d/1s6OwTi_WC-pS21WLGQYI39yw2m42ZlVolUXBclljXB4/edit?usp=sharing

R=msisov@chromium.org

Bug: 896640, 1099418
Change-Id: I8a19670fd4ad64d49a9aa202548c22065870dd90
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2401319
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Reviewed-by: default avatarMaksim Sisov (GMT+2) <msisov@igalia.com>
Reviewed-by: default avatarAntonio Gomes <tonikitoo@igalia.com>
Cr-Commit-Position: refs/heads/master@{#823987}
parent a1975778
......@@ -165,6 +165,7 @@ source_set("wayland") {
"//mojo/public/cpp/system",
"//skia",
"//third_party/wayland-protocols:cursor_shapes_protocol",
"//third_party/wayland-protocols:extended_drag",
"//third_party/wayland-protocols:gtk_primary_selection_protocol",
"//third_party/wayland-protocols:keyboard_extension_protocol",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
......
......@@ -6,6 +6,7 @@
#include <aura-shell-client-protocol.h>
#include <cursor-shapes-unstable-v1-client-protocol.h>
#include <extended-drag-unstable-v1-client-protocol.h>
#include <gtk-primary-selection-client-protocol.h>
#include <keyboard-extension-unstable-v1-client-protocol.h>
#include <linux-dmabuf-unstable-v1-client-protocol.h>
......@@ -253,6 +254,21 @@ const wl_interface* ObjectTraits<zcr_cursor_shapes_v1>::interface =
void (*ObjectTraits<zcr_cursor_shapes_v1>::deleter)(zcr_cursor_shapes_v1*) =
&zcr_cursor_shapes_v1_destroy;
const wl_interface* ObjectTraits<zcr_extended_drag_v1>::interface =
&zcr_extended_drag_v1_interface;
void (*ObjectTraits<zcr_extended_drag_v1>::deleter)(zcr_extended_drag_v1*) =
&zcr_extended_drag_v1_destroy;
const wl_interface* ObjectTraits<zcr_extended_drag_source_v1>::interface =
&zcr_extended_drag_source_v1_interface;
void (*ObjectTraits<zcr_extended_drag_source_v1>::deleter)(
zcr_extended_drag_source_v1*) = &zcr_extended_drag_source_v1_destroy;
const wl_interface* ObjectTraits<zcr_extended_drag_offer_v1>::interface =
&zcr_extended_drag_offer_v1_interface;
void (*ObjectTraits<zcr_extended_drag_offer_v1>::deleter)(
zcr_extended_drag_offer_v1*) = &zcr_extended_drag_offer_v1_destroy;
const wl_interface* ObjectTraits<zcr_keyboard_extension_v1>::interface =
&zcr_keyboard_extension_v1_interface;
void (*ObjectTraits<zcr_keyboard_extension_v1>::deleter)(
......
......@@ -51,6 +51,9 @@ struct zaura_surface;
struct zcr_cursor_shapes_v1;
struct zcr_keyboard_extension_v1;
struct zcr_extended_keyboard_v1;
struct zcr_extended_drag_v1;
struct zcr_extended_drag_source_v1;
struct zcr_extended_drag_offer_v1;
struct zwp_linux_dmabuf_v1;
struct zwp_linux_buffer_release_v1;
struct zwp_linux_explicit_synchronization_v1;
......@@ -330,6 +333,24 @@ struct ObjectTraits<zcr_cursor_shapes_v1> {
static void (*deleter)(zcr_cursor_shapes_v1*);
};
template <>
struct ObjectTraits<zcr_extended_drag_v1> {
static const wl_interface* interface;
static void (*deleter)(zcr_extended_drag_v1*);
};
template <>
struct ObjectTraits<zcr_extended_drag_source_v1> {
static const wl_interface* interface;
static void (*deleter)(zcr_extended_drag_source_v1*);
};
template <>
struct ObjectTraits<zcr_extended_drag_offer_v1> {
static const wl_interface* interface;
static void (*deleter)(zcr_extended_drag_offer_v1*);
};
template <>
struct ObjectTraits<zcr_keyboard_extension_v1> {
static const wl_interface* interface;
......
......@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include <extended-drag-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
......@@ -69,6 +70,7 @@ constexpr uint32_t kMinAuraShellVersion = 11;
constexpr uint32_t kMinWlDrmVersion = 2;
constexpr uint32_t kMinWlOutputVersion = 2;
constexpr uint32_t kMaxXdgDecorationVersion = 1;
constexpr uint32_t kMaxExtendedDragVersion = 1;
} // namespace
WaylandConnection::WaylandConnection() = default;
......@@ -447,6 +449,14 @@ void WaylandConnection::Global(void* data,
connection->xdg_decoration_manager_ =
wl::Bind<struct zxdg_decoration_manager_v1>(registry, name,
kMaxXdgDecorationVersion);
} else if (!connection->extended_drag_v1_ &&
strcmp(interface, "zcr_extended_drag_v1") == 0) {
connection->extended_drag_v1_ =
wl::Bind<zcr_extended_drag_v1>(registry, name, kMaxExtendedDragVersion);
if (!connection->extended_drag_v1_) {
LOG(ERROR) << "Failed to bind to zcr_extended_drag_v1 global";
return;
}
}
connection->ScheduleFlush();
......
......@@ -82,6 +82,9 @@ class WaylandConnection {
zxdg_decoration_manager_v1* xdg_decoration_manager_v1() const {
return xdg_decoration_manager_.get();
}
zcr_extended_drag_v1* extended_drag_v1() const {
return extended_drag_v1_.get();
}
void set_serial(uint32_t serial, EventType event_type) {
serial_ = {serial, event_type};
......@@ -209,6 +212,7 @@ class WaylandConnection {
wl::Object<zwp_linux_explicit_synchronization_v1>
linux_explicit_synchronization_;
wl::Object<zxdg_decoration_manager_v1> xdg_decoration_manager_;
wl::Object<zcr_extended_drag_v1> extended_drag_v1_;
// Event source instance. Must be declared before input objects so it
// outlives them so thus being able to properly handle their destruction.
......
......@@ -132,6 +132,9 @@ void WaylandToplevelWindow::Show(bool inactive) {
}
UpdateBufferScale(false);
if (auto* drag_controller = connection()->window_drag_controller())
drag_controller->OnToplevelWindowCreated(this);
}
void WaylandToplevelWindow::Hide() {
......
......@@ -4,6 +4,9 @@
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include <extended-drag-unstable-v1-client-protocol.h>
#include <wayland-client-protocol.h>
#include <cstdint>
#include <memory>
#include <ostream>
......@@ -23,8 +26,11 @@
#include "ui/events/platform/scoped_event_dispatcher.h"
#include "ui/events/platform_event.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.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/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
......@@ -35,6 +41,7 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
......@@ -49,6 +56,30 @@ constexpr uint32_t kDndActionWindowDrag =
} // namespace
class WaylandWindowDragController::ExtendedDragSource {
public:
ExtendedDragSource(const WaylandConnection& connection,
wl_data_source* source) {
DCHECK(connection.extended_drag_v1());
uint32_t options = ZCR_EXTENDED_DRAG_V1_OPTIONS_ALLOW_SWALLOW |
ZCR_EXTENDED_DRAG_V1_OPTIONS_ALLOW_DROP_NO_TARGET |
ZCR_EXTENDED_DRAG_V1_OPTIONS_LOCK_CURSOR;
source_.reset(zcr_extended_drag_v1_get_extended_drag_source(
connection.extended_drag_v1(), source, options));
DCHECK(source_);
}
void SetDraggedWindow(WaylandToplevelWindow* window,
const gfx::Vector2d& offset) {
auto* surface = window ? window->root_surface()->surface() : nullptr;
zcr_extended_drag_source_v1_drag(source_.get(), surface, offset.x(),
offset.y());
}
private:
wl::Object<zcr_extended_drag_source_v1> source_;
};
WaylandWindowDragController::WaylandWindowDragController(
WaylandConnection* connection,
WaylandDataDeviceManager* device_manager,
......@@ -82,11 +113,16 @@ bool WaylandWindowDragController::StartDragSession() {
data_source_->Offer({kMimeTypeChromiumWindow});
data_source_->SetAction(DragDropTypes::DRAG_MOVE);
// TODO(crbug.com/1099418): Use dragged window's surface as icon surface
// once "immediate drag" protocol extensions are available.
if (IsExtendedDragAvailable()) {
extended_drag_source_ = std::make_unique<ExtendedDragSource>(
*connection_, data_source_->data_source());
} else {
LOG(ERROR) << "zcr_extended_drag_v1 extension not available! "
<< "Window/Tab dragging won't be fully functional.";
}
data_device_->StartDrag(*data_source_, *origin_window_,
/*icon_surface=*/nullptr, this);
pointer_grab_owner_ = origin_window_;
// Observe window so we can take ownership of the origin surface in case it
......@@ -97,14 +133,13 @@ bool WaylandWindowDragController::StartDragSession() {
bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
const gfx::Vector2d& offset) {
DCHECK_EQ(state_, State::kAttached);
DCHECK_GE(state_, State::kAttached);
DCHECK(window);
dragged_window_ = window;
drag_offset_ = offset;
SetDraggedWindow(window, offset);
state_ = State::kDetached;
RunLoop();
dragged_window_ = nullptr;
SetDraggedWindow(nullptr, {});
DCHECK(state_ == State::kAttached || state_ == State::kDropped);
bool dropped = state_ == State::kDropped;
......@@ -141,6 +176,8 @@ void WaylandWindowDragController::OnDragOffer(
DCHECK_GE(state_, State::kAttached);
DCHECK(offer);
DCHECK(!data_offer_);
VLOG(1) << "OnOffer. mime_types=" << offer->mime_types().size();
data_offer_ = std::move(offer);
}
......@@ -246,6 +283,7 @@ void WaylandWindowDragController::OnDataSourceFinish(bool completed) {
// Release DND objects.
data_offer_.reset();
data_source_.reset();
extended_drag_source_.reset();
origin_surface_.reset();
origin_window_ = nullptr;
dragged_window_ = nullptr;
......@@ -287,8 +325,27 @@ uint32_t WaylandWindowDragController::DispatchEvent(
return POST_DISPATCH_PERFORM_DEFAULT;
}
void WaylandWindowDragController::OnToplevelWindowCreated(
WaylandToplevelWindow* window) {
// Skip unless a toplevel window is getting visible while in attached mode.
// E.g: A window/tab is being detached in a tab dragging session.
if (state_ != State::kAttached)
return;
DCHECK(window);
auto origin = window->GetBounds().origin();
gfx::Vector2d offset = gfx::ToFlooredPoint(pointer_location_) - origin;
VLOG(1) << "Toplevel window created (detached)."
<< " widget=" << window->GetWidget()
<< " calculated_offset=" << offset.ToString();
SetDraggedWindow(window, offset);
state_ = State::kDetached;
}
void WaylandWindowDragController::OnWindowRemoved(WaylandWindow* window) {
DCHECK_NE(state_, State::kIdle);
DCHECK_NE(window, dragged_window_);
if (window == origin_window_)
origin_surface_ = origin_window_->TakeWaylandSurface();
}
......@@ -334,20 +391,18 @@ void WaylandWindowDragController::HandleDropAndResetState() {
}
void WaylandWindowDragController::RunLoop() {
DCHECK_EQ(state_, State::kAttached);
DCHECK_EQ(state_, State::kDetached);
DCHECK(dragged_window_);
VLOG(1) << "Starting drag loop. widget=" << dragged_window_->GetWidget()
<< " offset=" << drag_offset_.ToString();
// TODO(crbug.com/896640): Handle cursor
auto old_dispatcher = std::move(nested_dispatcher_);
nested_dispatcher_ =
PlatformEventSource::GetInstance()->OverrideDispatcher(this);
base::WeakPtr<WaylandWindowDragController> alive(weak_factory_.GetWeakPtr());
state_ = State::kDetached;
base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
quit_loop_closure_ = loop.QuitClosure();
loop.Run();
......@@ -367,6 +422,24 @@ void WaylandWindowDragController::QuitLoop() {
std::move(quit_loop_closure_).Run();
}
void WaylandWindowDragController::SetDraggedWindow(
WaylandToplevelWindow* window,
const gfx::Vector2d& offset) {
if (dragged_window_ == window && offset == drag_offset_)
return;
dragged_window_ = window;
drag_offset_ = offset;
// TODO(crbug.com/896640): Fallback when extended-drag is not available.
if (extended_drag_source_)
extended_drag_source_->SetDraggedWindow(dragged_window_, drag_offset_);
}
bool WaylandWindowDragController::IsExtendedDragAvailable() const {
return !!connection_->extended_drag_v1();
}
std::ostream& operator<<(std::ostream& out,
WaylandWindowDragController::State state) {
return out << static_cast<int>(state);
......
......@@ -15,7 +15,9 @@
#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"
......@@ -68,7 +70,11 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
State state() const { return state_; }
void OnToplevelWindowCreated(WaylandToplevelWindow* window);
private:
class ExtendedDragSource;
// WaylandDataDevice::DragDelegate:
bool IsDragSource() const override;
void DrawIcon() override;
......@@ -103,6 +109,13 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
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_;
......@@ -119,6 +132,8 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment