summaryrefslogtreecommitdiff
path: root/chromium/ui/base/x/selection_owner.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/base/x/selection_owner.cc')
-rw-r--r--chromium/ui/base/x/selection_owner.cc233
1 files changed, 104 insertions, 129 deletions
diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc
index 76d95fdd45a..755b502b20a 100644
--- a/chromium/ui/base/x/selection_owner.cc
+++ b/chromium/ui/base/x/selection_owner.cc
@@ -7,11 +7,14 @@
#include <algorithm>
#include "base/logging.h"
+#include "base/memory/ref_counted_memory.h"
#include "ui/base/x/selection_utils.h"
+#include "ui/base/x/x11_util.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto.h"
namespace ui {
@@ -38,152 +41,142 @@ static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs,
// Returns a conservative max size of the data we can pass into
// XChangeProperty(). Copied from GTK.
-size_t GetMaxRequestSize(XDisplay* display) {
- long extended_max_size = XExtendedMaxRequestSize(display);
+size_t GetMaxRequestSize(x11::Connection* connection) {
+ long extended_max_size = connection->extended_max_request_length();
long max_size =
- (extended_max_size ? extended_max_size : XMaxRequestSize(display)) - 100;
+ (extended_max_size ? extended_max_size
+ : connection->setup().maximum_request_length) -
+ 100;
return std::min(static_cast<long>(0x40000),
std::max(static_cast<long>(0), max_size));
}
// Gets the value of an atom pair array property. On success, true is returned
// and the value is stored in |value|.
-bool GetAtomPairArrayProperty(XID window,
- XAtom property,
- std::vector<std::pair<XAtom,XAtom> >* value) {
- XAtom type = x11::None;
- int format = 0; // size in bits of each item in 'property'
- unsigned long num_items = 0;
- unsigned char* properties = nullptr;
- unsigned long remaining_bytes = 0;
-
- int result = XGetWindowProperty(gfx::GetXDisplay(), window, property,
- 0, // offset into property data to
- // read
- (~0L), // entire array
- x11::False, // deleted
- AnyPropertyType, &type, &format, &num_items,
- &remaining_bytes, &properties);
- gfx::XScopedPtr<unsigned char> scoped_properties(properties);
-
- if (result != x11::Success)
+bool GetAtomPairArrayProperty(
+ x11::Window window,
+ x11::Atom property,
+ std::vector<std::pair<x11::Atom, x11::Atom>>* value) {
+ std::vector<x11::Atom> atoms;
+ // Since this is an array of atom pairs, ensure ensure |atoms|
+ // has an element count that's a multiple of 2.
+ if (!ui::GetArrayProperty(window, property, &atoms) || atoms.size() % 2 != 0)
return false;
- // GTK does not require |type| to be kAtomPair.
- if (format != 32 || num_items % 2 != 0)
- return false;
-
- XAtom* atom_properties = reinterpret_cast<XAtom*>(properties);
value->clear();
- for (size_t i = 0; i < num_items; i+=2)
- value->push_back(std::make_pair(atom_properties[i], atom_properties[i+1]));
+ for (size_t i = 0; i < atoms.size(); i += 2)
+ value->push_back(std::make_pair(atoms[i], atoms[i + 1]));
return true;
}
+x11::Window GetSelectionOwner(x11::Atom selection) {
+ auto response = x11::Connection::Get()->GetSelectionOwner({selection}).Sync();
+ return response ? response->owner : x11::Window::None;
+}
+
+void SetSelectionOwner(x11::Window window,
+ x11::Atom selection,
+ x11::Time time = x11::Time::CurrentTime) {
+ x11::Connection::Get()->SetSelectionOwner({window, selection, time});
+}
+
} // namespace
-SelectionOwner::SelectionOwner(XDisplay* x_display,
- XID x_window,
- XAtom selection_name)
- : x_display_(x_display),
- x_window_(x_window),
+SelectionOwner::SelectionOwner(x11::Connection* connection,
+ x11::Window x_window,
+ x11::Atom selection_name)
+ : x_window_(x_window),
selection_name_(selection_name),
- max_request_size_(GetMaxRequestSize(x_display)) {}
+ max_request_size_(GetMaxRequestSize(connection)) {}
SelectionOwner::~SelectionOwner() {
// If we are the selection owner, we need to release the selection so we
// don't receive further events. However, we don't call ClearSelectionOwner()
// because we don't want to do this indiscriminately.
- if (XGetSelectionOwner(x_display_, selection_name_) == x_window_)
- XSetSelectionOwner(x_display_, selection_name_, x11::None,
- x11::CurrentTime);
+ if (GetSelectionOwner(selection_name_) == x_window_)
+ SetSelectionOwner(x11::Window::None, selection_name_);
}
-void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) {
+void SelectionOwner::RetrieveTargets(std::vector<x11::Atom>* targets) {
for (const auto& format_target : format_map_)
targets->push_back(format_target.first);
}
-void SelectionOwner::TakeOwnershipOfSelection(
- const SelectionFormatMap& data) {
+void SelectionOwner::TakeOwnershipOfSelection(const SelectionFormatMap& data) {
acquired_selection_timestamp_ = X11EventSource::GetInstance()->GetTimestamp();
- XSetSelectionOwner(x_display_, selection_name_, x_window_,
- acquired_selection_timestamp_);
+ SetSelectionOwner(x_window_, selection_name_,
+ static_cast<x11::Time>(acquired_selection_timestamp_));
- if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) {
+ if (GetSelectionOwner(selection_name_) == x_window_) {
// The X server agrees that we are the selection owner. Commit our data.
format_map_ = data;
}
}
void SelectionOwner::ClearSelectionOwner() {
- XSetSelectionOwner(x_display_, selection_name_, x11::None, x11::CurrentTime);
+ SetSelectionOwner(x11::Window::None, selection_name_);
format_map_ = SelectionFormatMap();
}
-void SelectionOwner::OnSelectionRequest(const XEvent& event) {
- XID requestor = event.xselectionrequest.requestor;
- XAtom requested_target = event.xselectionrequest.target;
- XAtom requested_property = event.xselectionrequest.property;
+void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
+ auto& request = *x11_event.As<x11::SelectionRequestEvent>();
+ auto requestor = request.requestor;
+ x11::Atom requested_target = request.target;
+ x11::Atom requested_property = request.property;
// Incrementally build our selection. By default this is a refusal, and we'll
// override the parts indicating success in the different cases.
- XEvent reply;
- reply.xselection.type = SelectionNotify;
- reply.xselection.requestor = requestor;
- reply.xselection.selection = event.xselectionrequest.selection;
- reply.xselection.target = requested_target;
- reply.xselection.property = x11::None; // Indicates failure
- reply.xselection.time = event.xselectionrequest.time;
+ x11::SelectionNotifyEvent reply{
+ .time = request.time,
+ .requestor = requestor,
+ .selection = request.selection,
+ .target = requested_target,
+ .property = x11::Atom::None, // Indicates failure
+ };
if (requested_target == gfx::GetAtom(kMultiple)) {
// The contents of |requested_property| should be a list of
// <target,property> pairs.
- std::vector<std::pair<XAtom,XAtom> > conversions;
- if (GetAtomPairArrayProperty(requestor,
- requested_property,
- &conversions)) {
- std::vector<XAtom> conversion_results;
- for (const std::pair<XAtom, XAtom>& conversion : conversions) {
+ std::vector<std::pair<x11::Atom, x11::Atom>> conversions;
+ if (GetAtomPairArrayProperty(requestor, requested_property, &conversions)) {
+ std::vector<x11::Atom> conversion_results;
+ for (const std::pair<x11::Atom, x11::Atom>& conversion : conversions) {
bool conversion_successful =
ProcessTarget(conversion.first, requestor, conversion.second);
conversion_results.push_back(conversion.first);
conversion_results.push_back(conversion_successful ? conversion.second
- : x11::None);
+ : x11::Atom::None);
}
// Set the property to indicate which conversions succeeded. This matches
// what GTK does.
- XChangeProperty(
- x_display_, requestor, requested_property, gfx::GetAtom(kAtomPair),
- 32, PropModeReplace,
- reinterpret_cast<const unsigned char*>(&conversion_results.front()),
- conversion_results.size());
+ ui::SetArrayProperty(requestor, requested_property,
+ gfx::GetAtom(kAtomPair), conversion_results);
- reply.xselection.property = requested_property;
+ reply.property = requested_property;
}
} else {
if (ProcessTarget(requested_target, requestor, requested_property))
- reply.xselection.property = requested_property;
+ reply.property = requested_property;
}
// Send off the reply.
- XSendEvent(x_display_, requestor, x11::False, 0, &reply);
+ ui::SendEvent(reply, requestor, x11::EventMask::NoEvent);
}
-void SelectionOwner::OnSelectionClear(const XEvent& event) {
+void SelectionOwner::OnSelectionClear(const x11::Event& event) {
DLOG(ERROR) << "SelectionClear";
// TODO(erg): If we receive a SelectionClear event while we're handling data,
// we need to delay clearing.
}
-bool SelectionOwner::CanDispatchPropertyEvent(const XEvent& event) {
- return event.xproperty.state == PropertyDelete &&
+bool SelectionOwner::CanDispatchPropertyEvent(const x11::Event& event) {
+ return event.As<x11::PropertyNotifyEvent>()->state == x11::Property::Delete &&
FindIncrementalTransferForEvent(event) != incremental_transfers_.end();
}
-void SelectionOwner::OnPropertyEvent(const XEvent& event) {
+void SelectionOwner::OnPropertyEvent(const x11::Event& event) {
auto it = FindIncrementalTransferForEvent(event);
if (it == incremental_transfers_.end())
return;
@@ -193,35 +186,31 @@ void SelectionOwner::OnPropertyEvent(const XEvent& event) {
CompleteIncrementalTransfer(it);
}
-bool SelectionOwner::ProcessTarget(XAtom target,
- XID requestor,
- XAtom property) {
- XAtom multiple_atom = gfx::GetAtom(kMultiple);
- XAtom save_targets_atom = gfx::GetAtom(kSaveTargets);
- XAtom targets_atom = gfx::GetAtom(kTargets);
- XAtom timestamp_atom = gfx::GetAtom(kTimestamp);
+bool SelectionOwner::ProcessTarget(x11::Atom target,
+ x11::Window requestor,
+ x11::Atom property) {
+ x11::Atom multiple_atom = gfx::GetAtom(kMultiple);
+ x11::Atom save_targets_atom = gfx::GetAtom(kSaveTargets);
+ x11::Atom targets_atom = gfx::GetAtom(kTargets);
+ x11::Atom timestamp_atom = gfx::GetAtom(kTimestamp);
if (target == multiple_atom || target == save_targets_atom)
return false;
if (target == timestamp_atom) {
- XChangeProperty(
- x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace,
- reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1);
+ ui::SetProperty(requestor, property, x11::Atom::INTEGER,
+ acquired_selection_timestamp_);
return true;
}
if (target == targets_atom) {
// We have been asked for TARGETS. Send an atom array back with the data
// types we support.
- std::vector<XAtom> targets = {timestamp_atom, targets_atom,
- save_targets_atom, multiple_atom};
+ std::vector<x11::Atom> targets = {timestamp_atom, targets_atom,
+ save_targets_atom, multiple_atom};
RetrieveTargets(&targets);
- XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&targets.front()),
- targets.size());
+ ui::SetArrayProperty(requestor, property, x11::Atom::ATOM, targets);
return true;
}
@@ -232,10 +221,8 @@ bool SelectionOwner::ProcessTarget(XAtom target,
// We must send the data back in several chunks due to a limitation in
// the size of X requests. Notify the selection requestor that the data
// will be sent incrementally by returning data of type "INCR".
- long length = it->second->size();
- XChangeProperty(x_display_, requestor, property, gfx::GetAtom(kIncr), 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&length), 1);
+ uint32_t length = it->second->size();
+ ui::SetProperty(requestor, property, gfx::GetAtom(kIncr), length);
// Wait for the selection requestor to indicate that it has processed
// the selection result before sending the first chunk of data. The
@@ -243,10 +230,10 @@ bool SelectionOwner::ProcessTarget(XAtom target,
base::TimeTicks timeout =
base::TimeTicks::Now() +
base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
- incremental_transfers_.push_back(IncrementalTransfer(
+ incremental_transfers_.emplace_back(
requestor, target, property,
std::make_unique<XScopedEventSelector>(requestor, PropertyChangeMask),
- it->second, 0, timeout));
+ it->second, 0, timeout);
// Start a timer to abort the data transfer in case that the selection
// requestor does not support the INCR property or gets destroyed during
@@ -258,15 +245,9 @@ bool SelectionOwner::ProcessTarget(XAtom target,
this, &SelectionOwner::AbortStaleIncrementalTransfers);
}
} else {
- XChangeProperty(
- x_display_,
- requestor,
- property,
- target,
- 8,
- PropModeReplace,
- const_cast<unsigned char*>(it->second->front()),
- it->second->size());
+ auto& mem = it->second;
+ std::vector<uint8_t> data(mem->data(), mem->data() + mem->size());
+ ui::SetArrayProperty(requestor, property, target, data);
}
return true;
}
@@ -279,17 +260,13 @@ bool SelectionOwner::ProcessTarget(XAtom target,
void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
size_t remaining = transfer->data->size() - transfer->offset;
size_t chunk_length = std::min(remaining, max_request_size_);
- XChangeProperty(
- x_display_,
- transfer->window,
- transfer->property,
- transfer->target,
- 8,
- PropModeReplace,
- const_cast<unsigned char*>(transfer->data->front() + transfer->offset),
- chunk_length);
+ const uint8_t* data = transfer->data->front() + transfer->offset;
+ std::vector<uint8_t> buf(data, data + chunk_length);
+ ui::SetArrayProperty(transfer->window, transfer->property, transfer->target,
+ buf);
transfer->offset += chunk_length;
- transfer->timeout = base::TimeTicks::Now() +
+ transfer->timeout =
+ base::TimeTicks::Now() +
base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
// When offset == data->size(), we still need to transfer a zero-sized chunk
@@ -302,8 +279,8 @@ void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
void SelectionOwner::AbortStaleIncrementalTransfers() {
base::TimeTicks now = base::TimeTicks::Now();
- for (int i = static_cast<int>(incremental_transfers_.size()) - 1;
- i >= 0; --i) {
+ for (int i = static_cast<int>(incremental_transfers_.size()) - 1; i >= 0;
+ --i) {
if (incremental_transfers_[i].timeout <= now)
CompleteIncrementalTransfer(incremental_transfers_.begin() + i);
}
@@ -318,21 +295,20 @@ void SelectionOwner::CompleteIncrementalTransfer(
}
std::vector<SelectionOwner::IncrementalTransfer>::iterator
- SelectionOwner::FindIncrementalTransferForEvent(const XEvent& event) {
+SelectionOwner::FindIncrementalTransferForEvent(const x11::Event& event) {
for (auto it = incremental_transfers_.begin();
it != incremental_transfers_.end(); ++it) {
- if (it->window == event.xproperty.window &&
- it->property == event.xproperty.atom) {
+ const auto* prop = event.As<x11::PropertyNotifyEvent>();
+ if (it->window == prop->window && it->property == prop->atom)
return it;
- }
}
return incremental_transfers_.end();
}
SelectionOwner::IncrementalTransfer::IncrementalTransfer(
- XID window,
- XAtom target,
- XAtom property,
+ x11::Window window,
+ x11::Atom target,
+ x11::Atom property,
std::unique_ptr<XScopedEventSelector> event_selector,
const scoped_refptr<base::RefCountedMemory>& data,
int offset,
@@ -348,10 +324,9 @@ SelectionOwner::IncrementalTransfer::IncrementalTransfer(
SelectionOwner::IncrementalTransfer::IncrementalTransfer(
IncrementalTransfer&& other) = default;
-SelectionOwner::IncrementalTransfer& SelectionOwner::IncrementalTransfer::
-operator=(IncrementalTransfer&&) = default;
+SelectionOwner::IncrementalTransfer&
+SelectionOwner::IncrementalTransfer::operator=(IncrementalTransfer&&) = default;
-SelectionOwner::IncrementalTransfer::~IncrementalTransfer() {
-}
+SelectionOwner::IncrementalTransfer::~IncrementalTransfer() = default;
} // namespace ui