| Index: ui/base/x/selection_requestor.cc
|
| diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc
|
| deleted file mode 100644
|
| index 5cab04fd91e46f5e0e2cf5478b182e07f09dade8..0000000000000000000000000000000000000000
|
| --- a/ui/base/x/selection_requestor.cc
|
| +++ /dev/null
|
| @@ -1,321 +0,0 @@
|
| -// Copyright (c) 2013 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/base/x/selection_requestor.h"
|
| -
|
| -#include <algorithm>
|
| -#include <X11/Xlib.h>
|
| -
|
| -#include "base/run_loop.h"
|
| -#include "ui/base/x/selection_utils.h"
|
| -#include "ui/base/x/x11_util.h"
|
| -#include "ui/events/platform/platform_event_dispatcher.h"
|
| -#include "ui/events/platform/platform_event_source.h"
|
| -#include "ui/gfx/x/x11_types.h"
|
| -
|
| -namespace ui {
|
| -
|
| -namespace {
|
| -
|
| -const char kChromeSelection[] = "CHROME_SELECTION";
|
| -const char kIncr[] = "INCR";
|
| -
|
| -const char* kAtomsToCache[] = {
|
| - kChromeSelection,
|
| - kIncr,
|
| - NULL
|
| -};
|
| -
|
| -// The period of |abort_timer_|. Arbitrary but must be <= than
|
| -// kRequestTimeoutMs.
|
| -const int kTimerPeriodMs = 100;
|
| -
|
| -// The amount of time to wait for a request to complete before aborting it.
|
| -const int kRequestTimeoutMs = 10000;
|
| -
|
| -COMPILE_ASSERT(kTimerPeriodMs <= kRequestTimeoutMs,
|
| - timer_period_must_be_less_or_equal_to_request_timeout);
|
| -
|
| -// Combines |data| into a single RefCountedMemory object.
|
| -scoped_refptr<base::RefCountedMemory> CombineRefCountedMemory(
|
| - const std::vector<scoped_refptr<base::RefCountedMemory> >& data) {
|
| - if (data.size() == 1u)
|
| - return data[0];
|
| -
|
| - size_t length = 0;
|
| - for (size_t i = 0; i < data.size(); ++i)
|
| - length += data[i]->size();
|
| - std::vector<unsigned char> combined_data;
|
| - combined_data.reserve(length);
|
| -
|
| - for (size_t i = 0; i < data.size(); ++i) {
|
| - combined_data.insert(combined_data.end(),
|
| - data[i]->front(),
|
| - data[i]->front() + data[i]->size());
|
| - }
|
| - return scoped_refptr<base::RefCountedMemory>(
|
| - base::RefCountedBytes::TakeVector(&combined_data));
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -SelectionRequestor::SelectionRequestor(XDisplay* x_display,
|
| - XID x_window,
|
| - PlatformEventDispatcher* dispatcher)
|
| - : x_display_(x_display),
|
| - x_window_(x_window),
|
| - x_property_(None),
|
| - dispatcher_(dispatcher),
|
| - current_request_index_(0u),
|
| - atom_cache_(x_display_, kAtomsToCache) {
|
| - x_property_ = atom_cache_.GetAtom(kChromeSelection);
|
| -}
|
| -
|
| -SelectionRequestor::~SelectionRequestor() {}
|
| -
|
| -bool SelectionRequestor::PerformBlockingConvertSelection(
|
| - XAtom selection,
|
| - XAtom target,
|
| - scoped_refptr<base::RefCountedMemory>* out_data,
|
| - size_t* out_data_items,
|
| - XAtom* out_type) {
|
| - base::TimeTicks timeout =
|
| - base::TimeTicks::Now() +
|
| - base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
|
| - Request request(selection, target, timeout);
|
| - requests_.push_back(&request);
|
| - if (current_request_index_ == (requests_.size() - 1))
|
| - ConvertSelectionForCurrentRequest();
|
| - BlockTillSelectionNotifyForRequest(&request);
|
| -
|
| - std::vector<Request*>::iterator request_it = std::find(
|
| - requests_.begin(), requests_.end(), &request);
|
| - CHECK(request_it != requests_.end());
|
| - if (static_cast<int>(current_request_index_) >
|
| - request_it - requests_.begin()) {
|
| - --current_request_index_;
|
| - }
|
| - requests_.erase(request_it);
|
| -
|
| - if (requests_.empty())
|
| - abort_timer_.Stop();
|
| -
|
| - if (request.success) {
|
| - if (out_data)
|
| - *out_data = CombineRefCountedMemory(request.out_data);
|
| - if (out_data_items)
|
| - *out_data_items = request.out_data_items;
|
| - if (out_type)
|
| - *out_type = request.out_type;
|
| - }
|
| - return request.success;
|
| -}
|
| -
|
| -void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
|
| - XAtom selection,
|
| - XAtom target,
|
| - const std::vector<XAtom>& parameter) {
|
| - SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
|
| - PerformBlockingConvertSelection(selection, target, NULL, NULL, NULL);
|
| -}
|
| -
|
| -SelectionData SelectionRequestor::RequestAndWaitForTypes(
|
| - XAtom selection,
|
| - const std::vector<XAtom>& types) {
|
| - for (std::vector<XAtom>::const_iterator it = types.begin();
|
| - it != types.end(); ++it) {
|
| - scoped_refptr<base::RefCountedMemory> data;
|
| - XAtom type = None;
|
| - if (PerformBlockingConvertSelection(selection,
|
| - *it,
|
| - &data,
|
| - NULL,
|
| - &type) &&
|
| - type == *it) {
|
| - return SelectionData(type, data);
|
| - }
|
| - }
|
| -
|
| - return SelectionData();
|
| -}
|
| -
|
| -void SelectionRequestor::OnSelectionNotify(const XEvent& event) {
|
| - Request* request = GetCurrentRequest();
|
| - XAtom event_property = event.xselection.property;
|
| - if (!request ||
|
| - request->completed ||
|
| - request->selection != event.xselection.selection ||
|
| - request->target != event.xselection.target) {
|
| - // ICCCM requires us to delete the property passed into SelectionNotify.
|
| - if (event_property != None)
|
| - XDeleteProperty(x_display_, x_window_, event_property);
|
| - return;
|
| - }
|
| -
|
| - bool success = false;
|
| - if (event_property == x_property_) {
|
| - scoped_refptr<base::RefCountedMemory> out_data;
|
| - success = ui::GetRawBytesOfProperty(x_window_,
|
| - x_property_,
|
| - &out_data,
|
| - &request->out_data_items,
|
| - &request->out_type);
|
| - if (success) {
|
| - request->out_data.clear();
|
| - request->out_data.push_back(out_data);
|
| - }
|
| - }
|
| - if (event_property != None)
|
| - XDeleteProperty(x_display_, x_window_, event_property);
|
| -
|
| - if (request->out_type == atom_cache_.GetAtom(kIncr)) {
|
| - request->data_sent_incrementally = true;
|
| - request->out_data.clear();
|
| - request->out_data_items = 0u;
|
| - request->out_type = None;
|
| - request->timeout = base::TimeTicks::Now() +
|
| - base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
|
| - } else {
|
| - CompleteRequest(current_request_index_, success);
|
| - }
|
| -}
|
| -
|
| -bool SelectionRequestor::CanDispatchPropertyEvent(const XEvent& event) {
|
| - return event.xproperty.window == x_window_ &&
|
| - event.xproperty.atom == x_property_ &&
|
| - event.xproperty.state == PropertyNewValue;
|
| -}
|
| -
|
| -void SelectionRequestor::OnPropertyEvent(const XEvent& event) {
|
| - Request* request = GetCurrentRequest();
|
| - if (!request || !request->data_sent_incrementally)
|
| - return;
|
| -
|
| - scoped_refptr<base::RefCountedMemory> out_data;
|
| - size_t out_data_items = 0u;
|
| - Atom out_type = None;
|
| - bool success = ui::GetRawBytesOfProperty(x_window_,
|
| - x_property_,
|
| - &out_data,
|
| - &out_data_items,
|
| - &out_type);
|
| - if (!success) {
|
| - CompleteRequest(current_request_index_, false);
|
| - return;
|
| - }
|
| -
|
| - if (request->out_type != None && request->out_type != out_type) {
|
| - CompleteRequest(current_request_index_, false);
|
| - return;
|
| - }
|
| -
|
| - request->out_data.push_back(out_data);
|
| - request->out_data_items += out_data_items;
|
| - request->out_type = out_type;
|
| -
|
| - // Delete the property to tell the selection owner to send the next chunk.
|
| - XDeleteProperty(x_display_, x_window_, x_property_);
|
| -
|
| - request->timeout = base::TimeTicks::Now() +
|
| - base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
|
| -
|
| - if (out_data->size() == 0u)
|
| - CompleteRequest(current_request_index_, true);
|
| -}
|
| -
|
| -void SelectionRequestor::AbortStaleRequests() {
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| - for (size_t i = current_request_index_; i < requests_.size(); ++i) {
|
| - if (requests_[i]->timeout <= now)
|
| - CompleteRequest(i, false);
|
| - }
|
| -}
|
| -
|
| -void SelectionRequestor::CompleteRequest(size_t index, bool success) {
|
| - if (index >= requests_.size())
|
| - return;
|
| -
|
| - Request* request = requests_[index];
|
| - if (request->completed)
|
| - return;
|
| - request->success = success;
|
| - request->completed = true;
|
| -
|
| - if (index == current_request_index_) {
|
| - while (GetCurrentRequest() && GetCurrentRequest()->completed)
|
| - ++current_request_index_;
|
| - ConvertSelectionForCurrentRequest();
|
| - }
|
| -
|
| - if (!request->quit_closure.is_null())
|
| - request->quit_closure.Run();
|
| -}
|
| -
|
| -void SelectionRequestor::ConvertSelectionForCurrentRequest() {
|
| - Request* request = GetCurrentRequest();
|
| - if (request) {
|
| - XConvertSelection(x_display_,
|
| - request->selection,
|
| - request->target,
|
| - x_property_,
|
| - x_window_,
|
| - CurrentTime);
|
| - }
|
| -}
|
| -
|
| -void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
|
| - if (PlatformEventSource::GetInstance()) {
|
| - if (!abort_timer_.IsRunning()) {
|
| - abort_timer_.Start(FROM_HERE,
|
| - base::TimeDelta::FromMilliseconds(kTimerPeriodMs),
|
| - this,
|
| - &SelectionRequestor::AbortStaleRequests);
|
| - }
|
| -
|
| - base::MessageLoop::ScopedNestableTaskAllower allow_nested(
|
| - base::MessageLoopForUI::current());
|
| - base::RunLoop run_loop;
|
| - request->quit_closure = run_loop.QuitClosure();
|
| - run_loop.Run();
|
| -
|
| - // We cannot put logic to process the next request here because the RunLoop
|
| - // might be nested. For instance, request 'B' may start a RunLoop while the
|
| - // RunLoop for request 'A' is running. It is not possible to end the RunLoop
|
| - // for request 'A' without first ending the RunLoop for request 'B'.
|
| - } else {
|
| - // This occurs if PerformBlockingConvertSelection() is called during
|
| - // shutdown and the PlatformEventSource has already been destroyed.
|
| - while (!request->completed &&
|
| - request->timeout > base::TimeTicks::Now()) {
|
| - if (XPending(x_display_)) {
|
| - XEvent event;
|
| - XNextEvent(x_display_, &event);
|
| - dispatcher_->DispatchEvent(&event);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
|
| - return current_request_index_ == requests_.size() ?
|
| - NULL : requests_[current_request_index_];
|
| -}
|
| -
|
| -SelectionRequestor::Request::Request(XAtom selection,
|
| - XAtom target,
|
| - base::TimeTicks timeout)
|
| - : selection(selection),
|
| - target(target),
|
| - data_sent_incrementally(false),
|
| - out_data_items(0u),
|
| - out_type(None),
|
| - success(false),
|
| - timeout(timeout),
|
| - completed(false) {
|
| -}
|
| -
|
| -SelectionRequestor::Request::~Request() {
|
| -}
|
| -
|
| -} // namespace ui
|
|
|