Commit 8c330007 authored by Nick Diego Yamane's avatar Nick Diego Yamane Committed by Commit Bot

ozone/wayland: Decouple DataSource implementation from its client code

This contains a major rework of DataSource support in Ozone Wayland
backend. Just like other recent refactors in data exchange related code,
such as https://crrev.com/c/2205881, the primary goal of this one is to
decouple "client code" from core implementation and interface of
*DataSource classes, so making it easier to maintain, extend, read, etc
etc as well as maximizing code reusage and will reduce complexity to
implement use cases such as Tab/Window Dragging.

To accomplish it, this CL:

1. Switches DataSource implementations to a template-based (instead of
using inheritance) approach in order to support *slightly* different
backing protocol extensions and maximize code reusage and consistency
on what is shared. For now there are 2 variants, one for the standard
wl_data_source protocol object and another one for gtk-primary-selection
extension (and probably a new one coming soon [2]).

2. Introduces DataSource::Delegate interface, through which the relevant
data source events are forwarded to "client code", eg: WaylandClipboard,
WaylandDataDragController, etc.

3. Refactors DataSource clients, mainly WaylandClipboard, making use of
the new template class instances to reach a cleaner and easier to extend
implementation of PlatformClipboard, seamlessly supporting both regular
and primary selection clipboard buffers.

4. Get rid of unneeded classes and source files.

No functional changes is expected and follow up changes should be done
in the future to switch the Device and Offer counterparts to a similar
architecture.

[1] https://gitlab.gnome.org/GNOME/mutter/-/blob/master/src/wayland/protocol/gtk-primary-selection.xml
[2] https://bugs.chromium.org/p/chromium/issues/detail?id=1088132

Bug: 896640
Change-Id: Iaf035dd106c6ab9488f44cfd8fb425ff3cd354db
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2222147Reviewed-by: default avatarMaksim Sisov <msisov@igalia.com>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/master@{#776903}
parent 64281514
...@@ -43,8 +43,6 @@ source_set("wayland") { ...@@ -43,8 +43,6 @@ source_set("wayland") {
"host/gtk_primary_selection_device_manager.h", "host/gtk_primary_selection_device_manager.h",
"host/gtk_primary_selection_offer.cc", "host/gtk_primary_selection_offer.cc",
"host/gtk_primary_selection_offer.h", "host/gtk_primary_selection_offer.h",
"host/gtk_primary_selection_source.cc",
"host/gtk_primary_selection_source.h",
"host/shell_object_factory.cc", "host/shell_object_factory.cc",
"host/shell_object_factory.h", "host/shell_object_factory.h",
"host/shell_popup_wrapper.cc", "host/shell_popup_wrapper.cc",
...@@ -77,8 +75,6 @@ source_set("wayland") { ...@@ -77,8 +75,6 @@ source_set("wayland") {
"host/wayland_data_offer_base.h", "host/wayland_data_offer_base.h",
"host/wayland_data_source.cc", "host/wayland_data_source.cc",
"host/wayland_data_source.h", "host/wayland_data_source.h",
"host/wayland_data_source_base.cc",
"host/wayland_data_source_base.h",
"host/wayland_drm.cc", "host/wayland_drm.cc",
"host/wayland_drm.h", "host/wayland_drm.h",
"host/wayland_event_source.cc", "host/wayland_event_source.cc",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui { namespace ui {
...@@ -25,6 +26,14 @@ GtkPrimarySelectionDevice::GtkPrimarySelectionDevice( ...@@ -25,6 +26,14 @@ GtkPrimarySelectionDevice::GtkPrimarySelectionDevice(
GtkPrimarySelectionDevice::~GtkPrimarySelectionDevice() = default; GtkPrimarySelectionDevice::~GtkPrimarySelectionDevice() = default;
void GtkPrimarySelectionDevice::SetSelectionSource(
GtkPrimarySelectionSource* source) {
DCHECK(source);
gtk_primary_selection_device_set_selection(
data_device_.get(), source->data_source(), connection()->serial());
connection()->ScheduleFlush();
}
// static // static
void GtkPrimarySelectionDevice::OnDataOffer( void GtkPrimarySelectionDevice::OnDataOffer(
void* data, void* data,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
struct gtk_primary_selection_device; struct gtk_primary_selection_device;
...@@ -31,6 +32,8 @@ class GtkPrimarySelectionDevice : public WaylandDataDeviceBase { ...@@ -31,6 +32,8 @@ class GtkPrimarySelectionDevice : public WaylandDataDeviceBase {
return data_device_.get(); return data_device_.get();
} }
void SetSelectionSource(GtkPrimarySelectionSource* source);
private: private:
// gtk_primary_selection_device_listener callbacks // gtk_primary_selection_device_listener callbacks
static void OnDataOffer(void* data, static void OnDataOffer(void* data,
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include <memory> #include <memory>
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui { namespace ui {
...@@ -36,10 +36,12 @@ GtkPrimarySelectionDevice* GtkPrimarySelectionDeviceManager::GetDevice() { ...@@ -36,10 +36,12 @@ GtkPrimarySelectionDevice* GtkPrimarySelectionDeviceManager::GetDevice() {
} }
std::unique_ptr<GtkPrimarySelectionSource> std::unique_ptr<GtkPrimarySelectionSource>
GtkPrimarySelectionDeviceManager::CreateSource() { GtkPrimarySelectionDeviceManager::CreateSource(
GtkPrimarySelectionSource::Delegate* delegate) {
auto* data_source = auto* data_source =
gtk_primary_selection_device_manager_create_source(device_manager_.get()); gtk_primary_selection_device_manager_create_source(device_manager_.get());
return std::make_unique<GtkPrimarySelectionSource>(data_source, connection_); return std::make_unique<GtkPrimarySelectionSource>(data_source, connection_,
delegate);
} }
} // namespace ui } // namespace ui
...@@ -7,26 +7,31 @@ ...@@ -7,26 +7,31 @@
#include <memory> #include <memory>
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
struct gtk_primary_selection_device_manager;
namespace ui { namespace ui {
class GtkPrimarySelectionDevice; class GtkPrimarySelectionDevice;
class GtkPrimarySelectionSource;
class WaylandConnection; class WaylandConnection;
class GtkPrimarySelectionDeviceManager { class GtkPrimarySelectionDeviceManager {
public: public:
using DataSource = GtkPrimarySelectionSource;
using DataDevice = GtkPrimarySelectionDevice;
GtkPrimarySelectionDeviceManager( GtkPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* manager, gtk_primary_selection_device_manager* manager,
WaylandConnection* connection); WaylandConnection* connection);
GtkPrimarySelectionDeviceManager(const GtkPrimarySelectionDeviceManager&) =
delete;
GtkPrimarySelectionDeviceManager& operator=(
const GtkPrimarySelectionDeviceManager&) = delete;
~GtkPrimarySelectionDeviceManager(); ~GtkPrimarySelectionDeviceManager();
GtkPrimarySelectionDevice* GetDevice(); GtkPrimarySelectionDevice* GetDevice();
std::unique_ptr<GtkPrimarySelectionSource> CreateSource(); std::unique_ptr<GtkPrimarySelectionSource> CreateSource(
GtkPrimarySelectionSource::Delegate* delegate);
private: private:
wl::Object<gtk_primary_selection_device_manager> device_manager_; wl::Object<gtk_primary_selection_device_manager> device_manager_;
...@@ -34,8 +39,6 @@ class GtkPrimarySelectionDeviceManager { ...@@ -34,8 +39,6 @@ class GtkPrimarySelectionDeviceManager {
WaylandConnection* const connection_; WaylandConnection* const connection_;
std::unique_ptr<GtkPrimarySelectionDevice> device_; std::unique_ptr<GtkPrimarySelectionDevice> device_;
DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionDeviceManager);
}; };
} // namespace ui } // namespace ui
......
// Copyright 2019 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.
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
#include <gtk-primary-selection-client-protocol.h>
#include <string>
#include <vector>
#include "base/check.h"
#include "base/files/file_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
namespace ui {
GtkPrimarySelectionSource::GtkPrimarySelectionSource(
gtk_primary_selection_source* data_source,
WaylandConnection* connection)
: data_source_(data_source), connection_(connection) {
DCHECK(data_source_);
DCHECK(connection_);
static const struct gtk_primary_selection_source_listener
kDataSourceListener = {GtkPrimarySelectionSource::OnSend,
GtkPrimarySelectionSource::OnCancelled};
gtk_primary_selection_source_add_listener(data_source_.get(),
&kDataSourceListener, this);
}
GtkPrimarySelectionSource::~GtkPrimarySelectionSource() = default;
// static
void GtkPrimarySelectionSource::OnSend(void* data,
gtk_primary_selection_source* source,
const char* mime_type,
int32_t fd) {
GtkPrimarySelectionSource* self =
static_cast<GtkPrimarySelectionSource*>(data);
std::string contents;
base::Optional<std::vector<uint8_t>> mime_data;
self->GetClipboardData(mime_type, &mime_data);
if (!mime_data.has_value() && strcmp(mime_type, kMimeTypeTextUtf8) == 0)
self->GetClipboardData(kMimeTypeText, &mime_data);
contents.assign(mime_data->begin(), mime_data->end());
bool result =
base::WriteFileDescriptor(fd, contents.data(), contents.length());
DCHECK(result);
close(fd);
}
// static
void GtkPrimarySelectionSource::OnCancelled(
void* data,
gtk_primary_selection_source* source) {
GtkPrimarySelectionSource* self =
static_cast<GtkPrimarySelectionSource*>(data);
self->connection_->clipboard()->DataSourceCancelled(
ClipboardBuffer::kSelection);
}
void GtkPrimarySelectionSource::WriteToClipboard(
const PlatformClipboard::DataMap& data_map) {
for (const auto& data : data_map) {
gtk_primary_selection_source_offer(data_source_.get(), data.first.c_str());
if (strcmp(data.first.c_str(), kMimeTypeText) == 0)
gtk_primary_selection_source_offer(data_source_.get(), kMimeTypeTextUtf8);
}
auto* device = connection_->primary_selection_device_manager()->GetDevice();
gtk_primary_selection_device_set_selection(
device->data_device(), data_source_.get(), connection_->serial());
connection_->ScheduleFlush();
}
} // namespace ui
// Copyright 2019 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_GTK_PRIMARY_SELECTION_SOURCE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
#include "ui/ozone/public/platform_clipboard.h"
struct gtk_primary_selection_source;
namespace ui {
class WaylandConnection;
class GtkPrimarySelectionSource : public WaylandDataSourceBase {
public:
// Takes ownership of |data_source|.
GtkPrimarySelectionSource(gtk_primary_selection_source* data_source,
WaylandConnection* connection);
~GtkPrimarySelectionSource() override;
void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override;
private:
// gtk_primary_selection_source_listener callbacks
static void OnSend(void* data,
gtk_primary_selection_source* source,
const char* mime_type,
int32_t fd);
static void OnCancelled(void* data, gtk_primary_selection_source* source);
// The gtk_primary_selection_source wrapped by this instance.
wl::Object<gtk_primary_selection_source> data_source_;
WaylandConnection* const connection_;
DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionSource);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
...@@ -4,28 +4,137 @@ ...@@ -4,28 +4,137 @@
#include "ui/ozone/platform/wayland/host/wayland_clipboard.h" #include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
#include <memory>
#include <string> #include <string>
#include "base/check.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "ui/base/clipboard/clipboard_buffer.h" #include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h" #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace wl {
// Internal Wayland Clipboard interface. A wl::Clipboard implementation handles
// a single ui::ClipboardBuffer. With this common interface it is possible to
// seamlessly support different clipboard buffers backed by different underlying
// Wayland protocol objects.
class Clipboard {
public:
virtual ~Clipboard() = default;
// Synchronously retrieves the mime types list currently available to be read.
virtual std::vector<std::string> ReadMimeTypes() = 0;
// Asynchronously reads clipboard content with |mime_type| format. The result
// data is expected to arrive through WaylandClipboard::SetData().
// TODO(nickdiego): Decouple DataDevice impls from WaylandClipboard.
virtual bool Read(const std::string& mime_type) = 0;
// Synchronously stores and announces |data| as available from this clipboard.
virtual void Write(const ui::PlatformClipboard::DataMap* data) = 0;
// Tells if this clipboard instance is the current selection owner.
virtual bool IsSelectionOwner() const = 0;
};
// Templated wl::Clipboard implementation. Whereas DataSource is the data source
// class capable of creating data offers upon clipboard writes and communicates
// events through DataSource::Delegate, and DataDevice is its device counterpart
// providing read and write access to the underlying data selection-related
// protocol objects. See *_data_{source,device}.h for more details.
template <typename Manager,
typename DataSource = typename Manager::DataSource,
typename DataDevice = typename Manager::DataDevice>
class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
public:
explicit ClipboardImpl(Manager* manager) : manager_(manager) {}
ClipboardImpl(const ClipboardImpl&) = delete;
ClipboardImpl& operator=(const ClipboardImpl&) = delete;
virtual ~ClipboardImpl() = default;
virtual bool Read(const std::string& mime_type) override {
return GetDevice()->RequestSelectionData(mime_type);
}
std::vector<std::string> ReadMimeTypes() override {
return GetDevice()->GetAvailableMimeTypes();
}
virtual void Write(const ui::PlatformClipboard::DataMap* data) override {
if (!data || data->empty()) {
data_.clear();
source_.reset();
} else {
data_ = *data;
if (!source_)
source_ = manager_->CreateSource(this);
source_->Offer(GetMimeTypes());
GetDevice()->SetSelectionSource(source_.get());
}
}
bool IsSelectionOwner() const override { return !!source_; }
private:
DataDevice* GetDevice() { return manager_->GetDevice(); }
std::vector<std::string> GetMimeTypes() {
std::vector<std::string> mime_types;
for (const auto& data : data_) {
mime_types.push_back(data.first);
if (data.first == ui::kMimeTypeText)
mime_types.push_back(ui::kMimeTypeTextUtf8);
}
return mime_types;
}
// WaylandDataSource::Delegate:
void OnDataSourceFinish(bool completed) override {
if (!completed)
Write(nullptr);
}
void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override {
DCHECK(contents);
auto it = data_.find(mime_type);
if (it == data_.end() && mime_type == ui::kMimeTypeTextUtf8)
it = data_.find(ui::kMimeTypeText);
if (it != data_.end())
contents->assign(it->second.begin(), it->second.end());
}
// The device manager used to access data device and create data sources.
Manager* const manager_;
// The current data source used to offer clipboard data.
std::unique_ptr<DataSource> source_;
// The data currently stored in a given clipboard buffer.
ui::PlatformClipboard::DataMap data_;
};
} // namespace wl
namespace ui { namespace ui {
WaylandClipboard::WaylandClipboard( WaylandClipboard::WaylandClipboard(WaylandConnection* connection,
WaylandConnection* connection, WaylandDataDeviceManager* manager)
WaylandDataDeviceManager* data_device_manager) : connection_(connection),
: connection_(connection), data_device_manager_(data_device_manager) { copypaste_clipboard_(
std::make_unique<wl::ClipboardImpl<WaylandDataDeviceManager>>(
manager)) {
DCHECK(manager);
DCHECK(connection_); DCHECK(connection_);
DCHECK(data_device_manager_); DCHECK(copypaste_clipboard_);
} }
WaylandClipboard::~WaylandClipboard() = default; WaylandClipboard::~WaylandClipboard() = default;
...@@ -34,10 +143,8 @@ void WaylandClipboard::OfferClipboardData( ...@@ -34,10 +143,8 @@ void WaylandClipboard::OfferClipboardData(
ClipboardBuffer buffer, ClipboardBuffer buffer,
const PlatformClipboard::DataMap& data_map, const PlatformClipboard::DataMap& data_map,
PlatformClipboard::OfferDataClosure callback) { PlatformClipboard::OfferDataClosure callback) {
if (auto* data_source = GetDataSource(buffer)) { if (auto* clipboard = GetClipboard(buffer))
data_source->WriteToClipboard(data_map); clipboard->Write(&data_map);
data_source->set_data_map(data_map);
}
std::move(callback).Run(); std::move(callback).Run();
} }
...@@ -46,19 +153,18 @@ void WaylandClipboard::RequestClipboardData( ...@@ -46,19 +153,18 @@ void WaylandClipboard::RequestClipboardData(
const std::string& mime_type, const std::string& mime_type,
PlatformClipboard::DataMap* data_map, PlatformClipboard::DataMap* data_map,
PlatformClipboard::RequestDataClosure callback) { PlatformClipboard::RequestDataClosure callback) {
read_clipboard_closure_ = std::move(callback);
DCHECK(data_map); DCHECK(data_map);
data_map_ = data_map; data_map_ = data_map;
auto* device = GetDataDevice(buffer); read_clipboard_closure_ = std::move(callback);
if (!device || !device->RequestSelectionData(mime_type)) auto* clipboard = GetClipboard(buffer);
if (!clipboard || !clipboard->Read(mime_type))
SetData({}, mime_type); SetData({}, mime_type);
} }
bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) { bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kCopyPaste) if (auto* clipboard = GetClipboard(buffer))
return !!clipboard_data_source_; return clipboard->IsSelectionOwner();
else return false;
return !!primary_data_source_;
} }
void WaylandClipboard::SetSequenceNumberUpdateCb( void WaylandClipboard::SetSequenceNumberUpdateCb(
...@@ -71,21 +177,10 @@ void WaylandClipboard::SetSequenceNumberUpdateCb( ...@@ -71,21 +177,10 @@ void WaylandClipboard::SetSequenceNumberUpdateCb(
void WaylandClipboard::GetAvailableMimeTypes( void WaylandClipboard::GetAvailableMimeTypes(
ClipboardBuffer buffer, ClipboardBuffer buffer,
PlatformClipboard::GetMimeTypesClosure callback) { PlatformClipboard::GetMimeTypesClosure callback) {
auto* device = GetDataDevice(buffer); std::vector<std::string> mime_types;
std::move(callback).Run(!device ? device->GetAvailableMimeTypes() if (auto* clipboard = GetClipboard(buffer))
: std::vector<std::string>{}); mime_types = clipboard->ReadMimeTypes();
} std::move(callback).Run(mime_types);
void WaylandClipboard::DataSourceCancelled(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kCopyPaste) {
DCHECK(clipboard_data_source_);
SetData({}, {});
clipboard_data_source_.reset();
} else {
DCHECK(primary_data_source_);
SetData({}, {});
primary_data_source_.reset();
}
} }
void WaylandClipboard::SetData(const std::vector<uint8_t>& contents, void WaylandClipboard::SetData(const std::vector<uint8_t>& contents,
...@@ -108,51 +203,24 @@ void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) { ...@@ -108,51 +203,24 @@ void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) {
update_sequence_cb_.Run(buffer); update_sequence_cb_.Run(buffer);
} }
bool WaylandClipboard::IsPrimarySelectionSupported() const { wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
return !!GetDataDevice(ClipboardBuffer::kSelection); if (buffer == ClipboardBuffer::kCopyPaste)
} return copypaste_clipboard_.get();
WaylandDataDeviceBase* WaylandClipboard::GetDataDevice(
ClipboardBuffer buffer) const {
switch (buffer) {
case ClipboardBuffer::kCopyPaste: {
return connection_->data_device_manager()->GetDevice();
}
case ClipboardBuffer::kSelection: {
return connection_->primary_selection_device_manager()
? connection_->primary_selection_device_manager()->GetDevice()
: nullptr;
}
default: {
NOTREACHED();
return nullptr;
}
}
}
WaylandDataSourceBase* WaylandClipboard::GetDataSource(ClipboardBuffer buffer) { if (buffer == ClipboardBuffer::kSelection) {
switch (buffer) { if (auto* manager = connection_->primary_selection_device_manager()) {
case ClipboardBuffer::kCopyPaste: { if (!primary_selection_clipboard_) {
if (!clipboard_data_source_) { primary_selection_clipboard_ = std::make_unique<
clipboard_data_source_ = wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(manager);
connection_->data_device_manager()->CreateSource();
} }
return clipboard_data_source_.get(); return primary_selection_clipboard_.get();
}
case ClipboardBuffer::kSelection: {
if (!IsPrimarySelectionSupported())
return nullptr;
if (!primary_data_source_) {
primary_data_source_ =
connection_->primary_selection_device_manager()->CreateSource();
}
return primary_data_source_.get();
}
default: {
NOTREACHED();
return nullptr;
} }
// Primary selection extension not available.
return nullptr;
} }
NOTREACHED() << "Unsupported clipboard buffer: " << static_cast<int>(buffer);
return nullptr;
} }
} // namespace ui } // namespace ui
...@@ -5,30 +5,36 @@ ...@@ -5,30 +5,36 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/ozone/public/platform_clipboard.h" #include "ui/ozone/public/platform_clipboard.h"
namespace wl {
class Clipboard;
} // namespace wl
namespace ui { namespace ui {
class GtkPrimarySelectionSource;
class WaylandConnection; class WaylandConnection;
class WaylandDataDeviceBase;
class WaylandDataDeviceManager; class WaylandDataDeviceManager;
class WaylandDataSourceBase;
class WaylandDataSource;
// Handles clipboard operations. // Handles clipboard operations.
// //
// WaylandConnection's wl_data_device_manager wrapper object is required to be // WaylandDataDeviceManager singleton is required to be up and running for
// non-null for objects of this class so it can provide basic functionality. // WaylandClipboard to be minimally functional.
class WaylandClipboard : public PlatformClipboard { class WaylandClipboard : public PlatformClipboard {
public: public:
WaylandClipboard(WaylandConnection* connection, WaylandClipboard(WaylandConnection* connection,
WaylandDataDeviceManager* data_device_manager); WaylandDataDeviceManager* device_manager);
WaylandClipboard(const WaylandClipboard&) = delete;
WaylandClipboard& operator=(const WaylandClipboard&) = delete;
~WaylandClipboard() override; ~WaylandClipboard() override;
// PlatformClipboard. // PlatformClipboard.
...@@ -48,24 +54,21 @@ class WaylandClipboard : public PlatformClipboard { ...@@ -48,24 +54,21 @@ class WaylandClipboard : public PlatformClipboard {
void SetSequenceNumberUpdateCb( void SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) override; PlatformClipboard::SequenceNumberUpdateCb cb) override;
void DataSourceCancelled(ClipboardBuffer buffer); // TODO(nickdiego): Get rid of these methods once DataDevice implementations
// are decoupled from WaylandClipboard.
void SetData(const std::vector<uint8_t>& contents, void SetData(const std::vector<uint8_t>& contents,
const std::string& mime_type); const std::string& mime_type);
void UpdateSequenceNumber(ClipboardBuffer buffer); void UpdateSequenceNumber(ClipboardBuffer buffer);
private: private:
bool IsPrimarySelectionSupported() const; // Get the wl::Clipboard instance owning a given |buffer|. Can return null in
WaylandDataDeviceBase* GetDataDevice(ClipboardBuffer buffer) const; // case |buffer| is unsupported. E.g: primary selection is not available.
WaylandDataSourceBase* GetDataSource(ClipboardBuffer buffer); wl::Clipboard* GetClipboard(ClipboardBuffer buffer);
// WaylandConnection providing optional data device managers, e.g: gtk // WaylandConnection providing optional data device managers, e.g: gtk
// primary selection. // primary selection.
WaylandConnection* const connection_; WaylandConnection* const connection_;
// Owned by WaylandConnection and required to be non-null so that
// WaylandConnection can be of some usefulness.
WaylandDataDeviceManager* const data_device_manager_;
// Holds a temporary instance of the client's clipboard content // Holds a temporary instance of the client's clipboard content
// so that we can asynchronously write to it. // so that we can asynchronously write to it.
PlatformClipboard::DataMap* data_map_ = nullptr; PlatformClipboard::DataMap* data_map_ = nullptr;
...@@ -77,10 +80,8 @@ class WaylandClipboard : public PlatformClipboard { ...@@ -77,10 +80,8 @@ class WaylandClipboard : public PlatformClipboard {
// Stores the callback to be invoked upon data reading from clipboard. // Stores the callback to be invoked upon data reading from clipboard.
PlatformClipboard::RequestDataClosure read_clipboard_closure_; PlatformClipboard::RequestDataClosure read_clipboard_closure_;
std::unique_ptr<WaylandDataSource> clipboard_data_source_; const std::unique_ptr<wl::Clipboard> copypaste_clipboard_;
std::unique_ptr<GtkPrimarySelectionSource> primary_data_source_; std::unique_ptr<wl::Clipboard> primary_selection_clipboard_;
DISALLOW_COPY_AND_ASSIGN(WaylandClipboard);
}; };
} // namespace ui } // namespace ui
......
...@@ -68,6 +68,13 @@ void WaylandDataDevice::RequestData(WaylandDataOffer* offer, ...@@ -68,6 +68,13 @@ void WaylandDataDevice::RequestData(WaylandDataOffer* offer,
RegisterDeferredReadCallback(); RegisterDeferredReadCallback();
} }
void WaylandDataDevice::SetSelectionSource(WaylandDataSource* source) {
DCHECK(source);
wl_data_device_set_selection(data_device_.get(), source->data_source(),
connection()->serial());
connection()->ScheduleFlush();
}
void WaylandDataDevice::ReadDragDataFromFD( void WaylandDataDevice::ReadDragDataFromFD(
base::ScopedFD fd, base::ScopedFD fd,
base::OnceCallback<void(const PlatformClipboard::Data&)> callback) { base::OnceCallback<void(const PlatformClipboard::Data&)> callback) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/public/platform_clipboard.h" #include "ui/ozone/public/platform_clipboard.h"
namespace gfx { namespace gfx {
...@@ -24,7 +25,6 @@ class PointF; ...@@ -24,7 +25,6 @@ class PointF;
namespace ui { namespace ui {
class WaylandDataOffer; class WaylandDataOffer;
class WaylandDataSource;
class WaylandConnection; class WaylandConnection;
class WaylandWindow; class WaylandWindow;
...@@ -72,6 +72,8 @@ class WaylandDataDevice : public WaylandDataDeviceBase { ...@@ -72,6 +72,8 @@ class WaylandDataDevice : public WaylandDataDeviceBase {
// Returns the underlying wl_data_device singleton object. // Returns the underlying wl_data_device singleton object.
wl_data_device* data_device() const { return data_device_.get(); } wl_data_device* data_device() const { return data_device_.get(); }
void SetSelectionSource(WaylandDataSource* source);
private: private:
void ReadDragDataFromFD(base::ScopedFD fd, RequestDataCallback callback); void ReadDragDataFromFD(base::ScopedFD fd, RequestDataCallback callback);
......
...@@ -25,6 +25,7 @@ class WaylandDataDeviceBase { ...@@ -25,6 +25,7 @@ class WaylandDataDeviceBase {
// Returns MIME types given by the current data offer. // Returns MIME types given by the current data offer.
const std::vector<std::string>& GetAvailableMimeTypes() const; const std::vector<std::string>& GetAvailableMimeTypes() const;
// Extracts data of the specified MIME type from the data offer. // Extracts data of the specified MIME type from the data offer.
bool RequestSelectionData(const std::string& mime_type); bool RequestSelectionData(const std::string& mime_type);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include <wayland-client-protocol.h>
#include <memory> #include <memory>
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
...@@ -24,19 +26,21 @@ WaylandDataDeviceManager::~WaylandDataDeviceManager() = default; ...@@ -24,19 +26,21 @@ WaylandDataDeviceManager::~WaylandDataDeviceManager() = default;
WaylandDataDevice* WaylandDataDeviceManager::GetDevice() { WaylandDataDevice* WaylandDataDeviceManager::GetDevice() {
DCHECK(connection_->seat()); DCHECK(connection_->seat());
if (!data_device_) { if (!device_) {
data_device_ = std::make_unique<WaylandDataDevice>( device_ = std::make_unique<WaylandDataDevice>(
connection_, wl_data_device_manager_get_data_device( connection_, wl_data_device_manager_get_data_device(
device_manager_.get(), connection_->seat())); device_manager_.get(), connection_->seat()));
} }
DCHECK(data_device_); DCHECK(device_);
return data_device_.get(); return device_.get();
} }
std::unique_ptr<WaylandDataSource> WaylandDataDeviceManager::CreateSource() { std::unique_ptr<WaylandDataSource> WaylandDataDeviceManager::CreateSource(
WaylandDataSource::Delegate* delegate) {
wl_data_source* data_source = wl_data_source* data_source =
wl_data_device_manager_create_data_source(device_manager_.get()); wl_data_device_manager_create_data_source(device_manager_.get());
return std::make_unique<WaylandDataSource>(data_source, connection_); return std::make_unique<WaylandDataSource>(data_source, connection_,
delegate);
} }
} // namespace ui } // namespace ui
...@@ -5,36 +5,37 @@ ...@@ -5,36 +5,37 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
#include <wayland-client.h>
#include <memory> #include <memory>
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui { namespace ui {
class WaylandConnection; class WaylandConnection;
class WaylandDataDevice; class WaylandDataDevice;
class WaylandDataSource;
class WaylandDataDeviceManager { class WaylandDataDeviceManager {
public: public:
using DataSource = WaylandDataSource;
using DataDevice = WaylandDataDevice;
WaylandDataDeviceManager(wl_data_device_manager* device_manager, WaylandDataDeviceManager(wl_data_device_manager* device_manager,
WaylandConnection* connection); WaylandConnection* connection);
WaylandDataDeviceManager(const WaylandDataDeviceManager&) = delete;
WaylandDataDeviceManager& operator=(const WaylandDataDeviceManager&) = delete;
~WaylandDataDeviceManager(); ~WaylandDataDeviceManager();
WaylandDataDevice* GetDevice(); WaylandDataDevice* GetDevice();
std::unique_ptr<WaylandDataSource> CreateSource(); std::unique_ptr<WaylandDataSource> CreateSource(
WaylandDataSource::Delegate* delegate);
private: private:
wl::Object<wl_data_device_manager> device_manager_; wl::Object<wl_data_device_manager> device_manager_;
WaylandConnection* const connection_; WaylandConnection* const connection_;
std::unique_ptr<WaylandDataDevice> data_device_; std::unique_ptr<WaylandDataDevice> device_;
DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceManager);
}; };
} // namespace ui } // namespace ui
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/check.h" #include "base/check.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h" #include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
...@@ -91,9 +92,8 @@ void WaylandDataDragController::StartSession(const OSExchangeData& data, ...@@ -91,9 +92,8 @@ void WaylandDataDragController::StartSession(const OSExchangeData& data,
// Create new new data source and offers |data|. // Create new new data source and offers |data|.
if (!data_source_) if (!data_source_)
data_source_ = data_device_manager_->CreateSource(); data_source_ = data_device_manager_->CreateSource(this);
data_source_->Offer(data, this); Offer(data, operation);
data_source_->SetAction(operation);
// Create drag icon surface (if any) and store the data to be exchanged. // Create drag icon surface (if any) and store the data to be exchanged.
icon_surface_.reset(CreateIconSurfaceIfNeeded(data)); icon_surface_.reset(CreateIconSurfaceIfNeeded(data));
...@@ -214,7 +214,7 @@ void WaylandDataDragController::OnDragDrop() { ...@@ -214,7 +214,7 @@ void WaylandDataDragController::OnDragDrop() {
HandleUnprocessedMimeTypes(); HandleUnprocessedMimeTypes();
} }
void WaylandDataDragController::OnDragSourceFinish(bool completed) { void WaylandDataDragController::OnDataSourceFinish(bool completed) {
DCHECK(data_source_); DCHECK(data_source_);
if (origin_window_) if (origin_window_)
origin_window_->OnDragSessionClose(data_source_->dnd_action()); origin_window_->OnDragSessionClose(data_source_->dnd_action());
...@@ -226,13 +226,43 @@ void WaylandDataDragController::OnDragSourceFinish(bool completed) { ...@@ -226,13 +226,43 @@ void WaylandDataDragController::OnDragSourceFinish(bool completed) {
state_ = State::kIdle; state_ = State::kIdle;
} }
void WaylandDataDragController::OnDragSourceSend(const std::string& mime_type, void WaylandDataDragController::OnDataSourceSend(const std::string& mime_type,
std::string* buffer) { std::string* buffer) {
DCHECK(data_source_);
DCHECK(buffer); DCHECK(buffer);
DCHECK(data_); DCHECK(data_);
if (!wl::ExtractOSExchangeData(*data_, mime_type, buffer)) if (!wl::ExtractOSExchangeData(*data_, mime_type, buffer)) {
LOG(WARNING) << "Cannot deliver data of type " << mime_type LOG(WARNING) << "Cannot deliver data of type " << mime_type
<< " and no text representation is available."; << " and no text representation is available.";
}
}
void WaylandDataDragController::Offer(const OSExchangeData& data,
int operation) {
DCHECK(data_source_);
// Drag'n'drop manuals usually suggest putting data in order so the more
// specific a MIME type is, the earlier it occurs in the list. Wayland
// specs don't say anything like that, but here we follow that common
// practice: begin with URIs and end with plain text. Just in case.
std::vector<std::string> mime_types;
if (data.HasFile()) {
mime_types.push_back(kMimeTypeURIList);
}
if (data.HasURL(FilenameToURLPolicy::CONVERT_FILENAMES)) {
mime_types.push_back(kMimeTypeMozillaURL);
}
if (data.HasHtml()) {
mime_types.push_back(kMimeTypeHTML);
}
if (data.HasString()) {
mime_types.push_back(kMimeTypeTextUtf8);
mime_types.push_back(kMimeTypeText);
}
DCHECK(!mime_types.empty());
data_source_->Offer(mime_types);
data_source_->SetAction(operation);
} }
wl_surface* WaylandDataDragController::CreateIconSurfaceIfNeeded( wl_surface* WaylandDataDragController::CreateIconSurfaceIfNeeded(
......
...@@ -30,11 +30,11 @@ class WaylandShmBuffer; ...@@ -30,11 +30,11 @@ class WaylandShmBuffer;
// WaylandDataDragController implements regular data exchanging between Chromium // WaylandDataDragController implements regular data exchanging between Chromium
// and other client applications on top of the Wayland Drag and Drop protocol. // and other client applications on top of the Wayland Drag and Drop protocol.
// By implementing both DataDevice::DragDelegate and DataSource::DragDelegate, // By implementing both DataDevice::DragDelegate and DataSource::Delegate,
// it is responsible for handling both DND sessions initiated from Chromium // it is responsible for handling both DND sessions initiated from Chromium
// windows as well as those triggered by other clients. // windows as well as those triggered by other clients.
class WaylandDataDragController : public WaylandDataDevice::DragDelegate, class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
public WaylandDataSource::DragDelegate { public WaylandDataSource::Delegate {
public: public:
enum class State { kIdle, kStarted, kTransferring }; enum class State { kIdle, kStarted, kTransferring };
...@@ -57,6 +57,7 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, ...@@ -57,6 +57,7 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
private: private:
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, ReceiveDrag); FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, ReceiveDrag);
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag); FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag);
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDragWithText);
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest,
StartDragWithWrongMimeType); StartDragWithWrongMimeType);
...@@ -71,11 +72,12 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, ...@@ -71,11 +72,12 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
void OnDragLeave() override; void OnDragLeave() override;
void OnDragDrop() override; void OnDragDrop() override;
// WaylandDataSource::DragDelegate: // WaylandDataSource::Delegate:
void OnDragSourceFinish(bool completed) override; void OnDataSourceFinish(bool completed) override;
void OnDragSourceSend(const std::string& mime_type, void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override; std::string* contents) override;
void Offer(const OSExchangeData& data, int operation);
wl_surface* CreateIconSurfaceIfNeeded(const OSExchangeData& data); wl_surface* CreateIconSurfaceIfNeeded(const OSExchangeData& data);
void HandleUnprocessedMimeTypes(); void HandleUnprocessedMimeTypes();
void OnMimeTypeDataTransferred(const PlatformClipboard::Data& contents); void OnMimeTypeDataTransferred(const PlatformClipboard::Data& contents);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "ui/base/dragdrop/file_info/file_info.h" #include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/base_event_utils.h" #include "ui/events/base_event_utils.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h" #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h" #include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
...@@ -114,6 +115,11 @@ class WaylandDataDragControllerTest : public WaylandTest { ...@@ -114,6 +115,11 @@ class WaylandDataDragControllerTest : public WaylandTest {
return connection_->data_device_manager()->GetDevice(); return connection_->data_device_manager()->GetDevice();
} }
base::string16 sample_text_for_dnd() const {
static auto text = base::ASCIIToUTF16(wl::kSampleTextForDragAndDrop);
return text;
}
protected: protected:
wl::TestDataDeviceManager* data_device_manager_; wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockDropHandler> drop_handler_; std::unique_ptr<MockDropHandler> drop_handler_;
...@@ -125,12 +131,9 @@ TEST_P(WaylandDataDragControllerTest, StartDrag) { ...@@ -125,12 +131,9 @@ TEST_P(WaylandDataDragControllerTest, StartDrag) {
// The client starts dragging. // The client starts dragging.
OSExchangeData os_exchange_data; OSExchangeData os_exchange_data;
os_exchange_data.SetString(sample_text_for_dnd());
int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE; int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
drag_controller()->StartSession(os_exchange_data, operation); drag_controller()->StartSession(os_exchange_data, operation);
WaylandDataSource::DragDataMap data;
data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
drag_controller()->data_source_->drag_data_map_ = data;
Sync(); Sync();
// The server reads the data and the callback gets it. // The server reads the data and the callback gets it.
...@@ -152,24 +155,20 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) { ...@@ -152,24 +155,20 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
bool restored_focus = window_->has_pointer_focus(); bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true); window_->SetPointerFocus(true);
// The client starts dragging offering data with wl::kTextMimeTypeUtf8 // The client starts dragging offering data with |kMimeTypeHTML|
// mime type.
OSExchangeData os_exchange_data; OSExchangeData os_exchange_data;
os_exchange_data.SetHtml(sample_text_for_dnd(), {});
int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE; int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
drag_controller()->StartSession(os_exchange_data, operation); drag_controller()->StartSession(os_exchange_data, operation);
WaylandDataSource::DragDataMap data;
data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
drag_controller()->data_source_->drag_data_map_ = data;
Sync(); Sync();
// The server should get an empty data buffer in ReadData callback // The server should get an empty data buffer in ReadData callback when trying
// when trying to read it. // to read it with a different mime type.
base::RunLoop run_loop; base::RunLoop run_loop;
auto callback = base::BindOnce( auto callback = base::BindOnce(
[](base::RunLoop* loop, PlatformClipboard::Data&& data) { [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
std::string result(data.begin(), data.end()); std::string result(data.begin(), data.end());
EXPECT_EQ("", result); EXPECT_TRUE(result.empty());
loop->Quit(); loop->Quit();
}, },
&run_loop); &run_loop);
...@@ -179,6 +178,34 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) { ...@@ -179,6 +178,34 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
window_->SetPointerFocus(restored_focus); window_->SetPointerFocus(restored_focus);
} }
TEST_P(WaylandDataDragControllerTest, StartDragWithText) {
bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
// The client starts dragging offering text mime type.
OSExchangeData os_exchange_data;
os_exchange_data.SetString(sample_text_for_dnd());
int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
drag_controller()->StartSession(os_exchange_data, operation);
Sync();
// The server should get a "text" representation in ReadData callback when
// trying to read it as mime type other than |kMimeTypeText| and
// |kTextMimeTypeUtf8|.
base::RunLoop run_loop;
auto callback = base::BindOnce(
[](base::RunLoop* loop, PlatformClipboard::Data&& data) {
std::string result(data.begin(), data.end());
EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
loop->Quit();
},
&run_loop);
data_device_manager_->data_source()->ReadData(kMimeTypeMozillaURL,
std::move(callback));
run_loop.Run();
window_->SetPointerFocus(restored_focus);
}
TEST_P(WaylandDataDragControllerTest, ReceiveDrag) { TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
auto* data_offer = data_device_manager_->data_device()->OnDataOffer(); auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
data_offer->OnOffer( data_offer->OnOffer(
......
...@@ -5,89 +5,97 @@ ...@@ -5,89 +5,97 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
#include <wayland-client.h>
#include <cstdint> #include <cstdint>
#include <map>
#include <string> #include <string>
#include <vector>
#include "base/gtest_prod_util.h" #include "base/notreached.h"
#include "base/logging.h"
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
#include "ui/ozone/public/platform_clipboard.h" struct wl_data_source;
struct gtk_primary_selection_source;
namespace wl {
template <typename T>
class DataSource;
} // namespace wl
namespace ui { namespace ui {
class OSExchangeData;
class WaylandConnection; class WaylandConnection;
// WaylandDataSource represents the source side of a WaylandDataOffer. It is // DataSource represents the source side of a DataOffer. It is created by the
// created by the source client in a data transfer and provides a way to // source client in a data transfer and provides a way to describe the offered
// describe the offered data (wl_data_source_offer) and a way to respond to // data and a way to respond to requests to transfer the data. There are a few
// requests to transfer the data (OnSend listener). // variants of Wayland protocol objects and extensions supporting different
class WaylandDataSource : public WaylandDataSourceBase { // features. E.g: regular copy/paste and drag operations are implemented by
public: // wl_data_source (along with its _device and _offer counterparts), etc.
using DragDataMap = std::map<std::string, std::string>; // Implementation wise, these variants are share a single class template, with
// specializations defined for each underlying supported extensions. Below are
// the type aliases for the variants currently supported.
//
// TODO(crbug.com/1088132): Support standard primary selection extension.
using WaylandDataSource = wl::DataSource<wl_data_source>;
using GtkPrimarySelectionSource = wl::DataSource<gtk_primary_selection_source>;
} // namespace ui
// DragDelegate is responsible for handling the wl_data_source events during namespace wl {
// drag and drop sessions.
class DragDelegate { // Template class implementing DataSource, whereas T is the underlying source
// type, e.g: wl_data_source, gtk_primary_selection_source, etc. This class
// is not supposed to be used directly, instead use the aliases defined above.
template <typename T>
class DataSource {
public:
class Delegate {
public: public:
virtual void OnDragSourceFinish(bool completed) = 0; virtual void OnDataSourceFinish(bool completed) = 0;
virtual void OnDragSourceSend(const std::string& mime_type, virtual void OnDataSourceSend(const std::string& mime_type,
std::string* contents) = 0; std::string* contents) = 0;
protected: protected:
virtual ~DragDelegate() = default; virtual ~Delegate() = default;
}; };
// Takes ownership of |data_source|. // Takes ownership of |data_source|.
WaylandDataSource(wl_data_source* data_source, WaylandConnection* connection); DataSource(T* data_source,
~WaylandDataSource() override; ui::WaylandConnection* connection,
Delegate* delegate);
void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override; DataSource(const DataSource<T>&) = delete;
void Offer(const ui::OSExchangeData& data, DragDelegate* drag_delegate); DataSource& operator=(const DataSource<T>&) = delete;
~DataSource() = default;
void Initialize();
void Offer(const std::vector<std::string>& mime_types);
void SetAction(int operation); void SetAction(int operation);
wl_data_source* data_source() const { return data_source_.get(); }
uint32_t dnd_action() const { return dnd_action_; } uint32_t dnd_action() const { return dnd_action_; }
T* data_source() const { return data_source_.get(); }
private: private:
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag); void HandleFinishEvent(bool completed);
FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, void HandleSendEvent(const std::string& mime_type, int32_t fd);
StartDragWithWrongMimeType);
static void OnTarget(void* data,
wl_data_source* source,
const char* mime_type);
static void OnSend(void* data,
wl_data_source* source,
const char* mime_type,
int32_t fd);
static void OnCancel(void* data, wl_data_source* source);
static void OnDnDDropPerformed(void* data, wl_data_source* source);
static void OnDnDFinished(void* data, wl_data_source* source);
static void OnAction(void* data, wl_data_source* source, uint32_t dnd_action);
void GetDragData(const std::string& mime_type, std::string* contents); static void OnSend(void* data, T* source, const char* mime_type, int32_t fd);
static void OnCancel(void* data, T* source);
static void OnDnDFinished(void* data, T* source);
static void OnAction(void* data, T* source, uint32_t dnd_action);
static void OnTarget(void* data, T* source, const char* mime_type);
static void OnDnDDropPerformed(void* data, T* source);
wl::Object<wl_data_source> data_source_; wl::Object<T> data_source_;
WaylandConnection* const connection_; ui::WaylandConnection* const connection_;
// Set when this used in DND sessions initiated from Chromium. Delegate* const delegate_;
DragDelegate* drag_delegate_ = nullptr;
DragDataMap drag_data_map_;
// Action selected by the compositor // Action selected by the compositor
uint32_t dnd_action_; uint32_t dnd_action_;
DISALLOW_COPY_AND_ASSIGN(WaylandDataSource);
}; };
} // namespace ui } // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_ #endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
// Copyright 2019 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.
#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
namespace ui {
WaylandDataSourceBase::WaylandDataSourceBase() = default;
WaylandDataSourceBase::~WaylandDataSourceBase() = default;
void WaylandDataSourceBase::GetClipboardData(
const std::string& mime_type,
base::Optional<std::vector<uint8_t>>* data) const {
auto it = data_map_.find(mime_type);
if (it == data_map_.end())
return;
data->emplace(it->second);
}
} // namespace ui
// Copyright 2019 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_DATA_SOURCE_BASE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_BASE_H_
#include "base/macros.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
// Implements high level (protocol-agnostic) interface to a Wayland data source.
class WaylandDataSourceBase {
public:
WaylandDataSourceBase();
virtual ~WaylandDataSourceBase();
void set_data_map(const PlatformClipboard::DataMap& data_map) {
data_map_ = data_map;
}
// Writes data to the system clipboard using the protocol-defined data source.
virtual void WriteToClipboard(const PlatformClipboard::DataMap& data_map) = 0;
protected:
void GetClipboardData(const std::string& mime_type,
base::Optional<std::vector<uint8_t>>* data) const;
private:
PlatformClipboard::DataMap data_map_;
DISALLOW_COPY_AND_ASSIGN(WaylandDataSourceBase);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_BASE_H_
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