0

Update clipboard xdg-desktop-portal for Wayland

With 1.18, portal has support for clipboard, but we need to update SelectionWrite/SelectionWriteDone to use it.

Change-Id: Ief94e1e55d833220cb27cb9e289b09dc95de7d91
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5117056
Reviewed-by: Yuwei Huang <yuweih@chromium.org>
Auto-Submit: Max Booth <maxbooth@chromium.org>
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: Lambros Lambrou <lambroslambrou@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1237687}
This commit is contained in:
Max Booth
2023-12-14 19:52:28 +00:00
committed by Chromium LUCI CQ
parent 351ed75293
commit 9c3810b95e
2 changed files with 40 additions and 50 deletions

@ -12,7 +12,6 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "remoting/base/constants.h" #include "remoting/base/constants.h"
#include "remoting/base/logging.h" #include "remoting/base/logging.h"
@ -151,25 +150,20 @@ void ClipboardPortalInjector::OnSetSelectionCallback(GObject* object,
} }
} }
void ClipboardPortalInjector::SelectionWrite() { void ClipboardPortalInjector::SelectionWrite(const uint serial) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(proxy_); DCHECK(proxy_);
DCHECK(cancellable_); DCHECK(cancellable_);
DCHECK(!session_handle_.empty()); DCHECK(!session_handle_.empty());
DCHECK(!write_serials_.empty()); DCHECK(serial);
DCHECK(!write_data_.empty()); DCHECK(!write_data_.empty());
GVariantBuilder serials_builder; write_serial_ = serial;
g_variant_builder_init(&serials_builder, G_VARIANT_TYPE("au"));
for (auto serial : write_serials_) {
g_variant_builder_add(&serials_builder, "u", serial);
}
write_serials_.clear();
Scoped<GError> error; Scoped<GError> error;
g_dbus_proxy_call_with_unix_fd_list( g_dbus_proxy_call_with_unix_fd_list(
proxy_, "SelectionWrite", proxy_, "SelectionWrite",
g_variant_new("(oau)", session_handle_.c_str(), &serials_builder), g_variant_new("(ou)", session_handle_.c_str(), write_serial_),
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, nullptr, cancellable_, G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, nullptr, cancellable_,
OnSelectionWriteCallback, this); OnSelectionWriteCallback, this);
} }
@ -185,7 +179,7 @@ void ClipboardPortalInjector::OnSelectionWriteCallback(GObject* object,
Scoped<GError> error; Scoped<GError> error;
Scoped<GUnixFDList> outlist; Scoped<GUnixFDList> outlist;
std::unordered_map<int, gboolean> request_successes; gboolean success;
Scoped<GVariant> variant(g_dbus_proxy_call_with_unix_fd_list_finish( Scoped<GVariant> variant(g_dbus_proxy_call_with_unix_fd_list_finish(
proxy, outlist.receive(), result, error.receive())); proxy, outlist.receive(), result, error.receive()));
@ -195,48 +189,40 @@ void ClipboardPortalInjector::OnSelectionWriteCallback(GObject* object,
} }
int32_t fd_id; int32_t fd_id;
guint serial; Scoped<GError> fd_error;
GVariantIter iterator; success = false;
g_variant_iter_init(&iterator, g_variant_get_child_value(variant.get(), 0));
while (g_variant_iter_loop(&iterator, "{uh}", &serial, &fd_id)) {
Scoped<GError> fd_error;
base::ScopedFD fd(
g_unix_fd_list_get(outlist.get(), fd_id, fd_error.receive()));
request_successes[serial] = false; fd_id = g_variant_get_handle(variant.get());
if (!fd.is_valid()) {
LOG(ERROR) << "Failed to get file descriptor from the list: " base::ScopedFD fd(
<< fd_error->message; g_unix_fd_list_get(outlist.get(), fd_id, fd_error.receive()));
} else {
request_successes[serial] = if (!fd.is_valid()) {
base::WriteFileDescriptor(fd.get(), that->write_data_); LOG(ERROR) << "Failed to get file descriptor from the list: "
if (!request_successes[serial]) { << fd_error->message;
LOG(ERROR) << "Failed to write clipboard data to file descriptor"; } else {
} success = base::WriteFileDescriptor(fd.get(), that->write_data_);
if (!success) {
LOG(ERROR) << "Failed to write clipboard data to file descriptor";
} }
} }
that->SelectionWriteDone(request_successes); that->SelectionWriteDone(that->write_serial_, success);
that->write_serial_ = 0;
} }
void ClipboardPortalInjector::SelectionWriteDone( void ClipboardPortalInjector::SelectionWriteDone(const uint serial,
const std::unordered_map<int, gboolean>& request_successes) { const gboolean success) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(proxy_); DCHECK(proxy_);
DCHECK(cancellable_); DCHECK(cancellable_);
DCHECK(!session_handle_.empty()); DCHECK(!session_handle_.empty());
GVariantBuilder request_successes_builder; g_dbus_proxy_call(
g_variant_builder_init(&request_successes_builder, G_VARIANT_TYPE("a{ub}")); proxy_, "SelectionWriteDone",
for (const auto& [serial, success] : request_successes) { g_variant_new("(oub)", session_handle_.c_str(), serial, success),
g_variant_builder_add(&request_successes_builder, "{ub}", serial, success); G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_,
} OnSelectionWriteDoneCallback, this);
g_dbus_proxy_call(proxy_, "SelectionWriteDone",
g_variant_new("(oa{ub})", session_handle_.c_str(),
&request_successes_builder),
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_,
OnSelectionWriteDoneCallback, this);
} }
// static // static
@ -372,9 +358,15 @@ void ClipboardPortalInjector::OnSelectionTransferSignal(
g_variant_get(parameters, "(osu)", /*session_handle*/ nullptr, g_variant_get(parameters, "(osu)", /*session_handle*/ nullptr,
/*mime_type*/ nullptr, &serial); /*mime_type*/ nullptr, &serial);
that->write_serials_.insert(serial); if (!that->write_serial_) {
that->SelectionWrite(serial);
that->SelectionWrite(); } else {
// we only process one write request at a time, so tell the backend to
// release any extra serials it allocates.
LOG(ERROR)
<< "Received clipboard write serial while busy processing another.";
that->SelectionWriteDone(serial, false);
}
} }
// static // static

@ -44,9 +44,8 @@ class ClipboardPortalInjector {
private: private:
void SelectionRead(std::string mime_type); void SelectionRead(std::string mime_type);
void SelectionWrite(); void SelectionWrite(const uint serial);
void SelectionWriteDone( void SelectionWriteDone(const uint serial, const gboolean success);
const std::unordered_map<int, gboolean>& request_successes);
void SubscribeClipboardSignals(); void SubscribeClipboardSignals();
void UnsubscribeSignalHandlers(); void UnsubscribeSignalHandlers();
@ -91,8 +90,7 @@ class ClipboardPortalInjector {
std::unordered_set<std::string> writable_mime_type_set_ std::unordered_set<std::string> writable_mime_type_set_
GUARDED_BY_CONTEXT(sequence_checker_); GUARDED_BY_CONTEXT(sequence_checker_);
std::string write_data_ GUARDED_BY_CONTEXT(sequence_checker_); std::string write_data_ GUARDED_BY_CONTEXT(sequence_checker_);
std::unordered_set<guint> write_serials_ guint write_serial_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
GUARDED_BY_CONTEXT(sequence_checker_);
std::unordered_set<std::string> readable_mime_type_set_ std::unordered_set<std::string> readable_mime_type_set_
GUARDED_BY_CONTEXT(sequence_checker_); GUARDED_BY_CONTEXT(sequence_checker_);