Chromium Code Reviews| Index: ui/base/x/selection_requestor.cc |
| diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc |
| index 516e0e0398c558b5bb0de603fe6a175ab840af7a..ac092ea3257766af933312ebc6434fa787f3bcbf 100644 |
| --- a/ui/base/x/selection_requestor.cc |
| +++ b/ui/base/x/selection_requestor.cc |
| @@ -15,10 +15,22 @@ namespace ui { |
| namespace { |
| -const char kChromeSelection[] = "CHROME_SELECTION"; |
| +// Properties to be used in XConvertSelection() requests. The number of |
| +// properties is arbitrary. |
| +const char* kChromeSelectionProperties[] = { |
| + "CHROME_SELECTION0", |
| + "CHROME_SELECTION1", |
| + "CHROME_SELECTION2", |
| + "CHROME_SELECTION3", |
| + "CHROME_SELECTION4" |
| +}; |
| const char* kAtomsToCache[] = { |
| - kChromeSelection, |
| + kChromeSelectionProperties[0], |
| + kChromeSelectionProperties[1], |
| + kChromeSelectionProperties[2], |
| + kChromeSelectionProperties[3], |
| + kChromeSelectionProperties[4], |
| NULL |
| }; |
| @@ -26,65 +38,61 @@ const char* kAtomsToCache[] = { |
| SelectionRequestor::SelectionRequestor(Display* x_display, |
| Window x_window, |
| - Atom selection_name, |
| PlatformEventDispatcher* dispatcher) |
| : x_display_(x_display), |
| x_window_(x_window), |
| - selection_name_(selection_name), |
| dispatcher_(dispatcher), |
| + property_pool_(kChromeSelectionProperties, |
| + kChromeSelectionProperties |
| + + arraysize(kChromeSelectionProperties)), |
| atom_cache_(x_display_, kAtomsToCache) { |
| } |
| SelectionRequestor::~SelectionRequestor() {} |
| bool SelectionRequestor::PerformBlockingConvertSelection( |
| + Atom selection, |
| Atom target, |
| scoped_refptr<base::RefCountedMemory>* out_data, |
| size_t* out_data_items, |
| Atom* out_type) { |
| - // The name of the property that we are either: |
| - // - Passing as a parameter with the XConvertSelection() request. |
| - // OR |
| - // - Asking the selection owner to set on |x_window_|. |
| - Atom property = atom_cache_.GetAtom(kChromeSelection); |
| - |
| - XConvertSelection(x_display_, |
| - selection_name_, |
| - target, |
| - property, |
| - x_window_, |
| - CurrentTime); |
| - |
| - // Now that we've thrown our message off to the X11 server, we block waiting |
| - // for a response. |
| - PendingRequest pending_request(target); |
| - BlockTillSelectionNotifyForRequest(&pending_request); |
| - |
| - bool success = false; |
| - if (pending_request.returned_property == property) { |
| - success = ui::GetRawBytesOfProperty(x_window_, |
| - pending_request.returned_property, |
| - out_data, out_data_items, out_type); |
| - } |
| - if (pending_request.returned_property != None) |
| - XDeleteProperty(x_display_, x_window_, pending_request.returned_property); |
| + // Find a property for XConvertSelection() to use. The selection owner will |
| + // set |property| on |xwindow_| with the data for the requested target. If |
| + // there is no available property, make the request fail. |
| + if (property_pool_.empty()) |
| + return false; |
| + |
| + const char* property_name = property_pool_.back(); |
| + property_pool_.pop_back(); |
|
Daniel Erat
2014/07/15 01:04:09
with the disclaimer that i don't know much about s
pkotwicz
2014/07/15 02:07:24
The problem is that there are callers of clipboard
Daniel Erat
2014/07/15 03:32:01
oh. is the nested message loop in BlockTillSelecti
|
| + bool success = PerformBlockingConvertSelectionImpl(selection, target, |
| + property_name, out_data, out_data_items, out_type); |
| + property_pool_.push_back(property_name); |
| return success; |
| } |
| void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( |
| + Atom selection, |
| Atom target, |
| const std::vector< ::Atom>& parameter) { |
| - SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); |
| - PerformBlockingConvertSelection(target, NULL, NULL, NULL); |
| + if (property_pool_.empty()) |
| + return; |
| + const char* property_name = property_pool_.back(); |
| + property_pool_.pop_back(); |
| + SetAtomArrayProperty(x_window_, property_name, "ATOM", parameter); |
| + PerformBlockingConvertSelectionImpl(selection, target, property_name, NULL, |
| + NULL, NULL); |
| + property_pool_.push_back(property_name); |
| } |
| SelectionData SelectionRequestor::RequestAndWaitForTypes( |
| + Atom selection, |
| const std::vector< ::Atom>& types) { |
| for (std::vector< ::Atom>::const_iterator it = types.begin(); |
| it != types.end(); ++it) { |
| scoped_refptr<base::RefCountedMemory> data; |
| ::Atom type = None; |
| - if (PerformBlockingConvertSelection(*it, |
| + if (PerformBlockingConvertSelection(selection, |
| + *it, |
| &data, |
| NULL, |
| &type) && |
| @@ -101,14 +109,12 @@ void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) { |
| // there are multiple pending requests on the same target, satisfy them in |
| // FIFO order. |
| PendingRequest* request_notified = NULL; |
| - if (selection_name_ == event.selection) { |
| - for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin(); |
| - iter != pending_requests_.end(); ++iter) { |
| - PendingRequest* request = *iter; |
| - if (request->returned) |
| - continue; |
| - if (request->target != event.target) |
| - continue; |
| + for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin(); |
| + iter != pending_requests_.end(); ++iter) { |
| + PendingRequest* request = *iter; |
| + if (!request->returned && |
| + request->selection == event.selection && |
| + request->target == event.target) { |
| request_notified = request; |
| break; |
| } |
| @@ -133,6 +139,37 @@ void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) { |
| request_notified->quit_closure.Run(); |
| } |
| +bool SelectionRequestor::PerformBlockingConvertSelectionImpl( |
| + Atom selection, |
| + Atom target, |
| + const char* property_name, |
| + scoped_refptr<base::RefCountedMemory>* out_data, |
| + size_t* out_data_items, |
| + Atom* out_type) { |
| + Atom property = atom_cache_.GetAtom(property_name); |
| + XConvertSelection(x_display_, |
| + selection, |
| + target, |
| + property, |
| + x_window_, |
| + CurrentTime); |
| + |
| + // Now that we've thrown our message off to the X11 server, we block waiting |
| + // for a response. |
| + PendingRequest pending_request(selection, target); |
| + BlockTillSelectionNotifyForRequest(&pending_request); |
| + |
| + bool success = false; |
| + if (pending_request.returned_property == property) { |
| + success = ui::GetRawBytesOfProperty(x_window_, |
| + pending_request.returned_property, |
| + out_data, out_data_items, out_type); |
| + } |
| + if (pending_request.returned_property != None) |
| + XDeleteProperty(x_display_, x_window_, pending_request.returned_property); |
| + return success; |
| +} |
| + |
| void SelectionRequestor::BlockTillSelectionNotifyForRequest( |
| PendingRequest* request) { |
| pending_requests_.push_back(request); |
| @@ -171,8 +208,10 @@ void SelectionRequestor::BlockTillSelectionNotifyForRequest( |
| pending_requests_.pop_back(); |
| } |
| -SelectionRequestor::PendingRequest::PendingRequest(Atom target) |
| - : target(target), |
| +SelectionRequestor::PendingRequest::PendingRequest(Atom requested_selection, |
| + Atom requested_target) |
| + : selection(requested_selection), |
| + target(requested_target), |
| returned_property(None), |
| returned(false) { |
| } |