diff options
Diffstat (limited to 'chromium/ui/base/x/selection_owner.cc')
-rw-r--r-- | chromium/ui/base/x/selection_owner.cc | 233 |
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 |