Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Unified Diff: ui/base/x/selection_owner.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/base/x/selection_owner.h ('k') | ui/base/x/selection_requestor.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/base/x/selection_owner.cc
diff --git a/ui/base/x/selection_owner.cc b/ui/base/x/selection_owner.cc
deleted file mode 100644
index b2b44c9d313a1b1e1bec86b94c9e79e412d4a582..0000000000000000000000000000000000000000
--- a/ui/base/x/selection_owner.cc
+++ /dev/null
@@ -1,384 +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_owner.h"
-
-#include <algorithm>
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-
-#include "base/logging.h"
-#include "ui/base/x/selection_utils.h"
-#include "ui/base/x/x11_foreign_window_manager.h"
-#include "ui/base/x/x11_util.h"
-
-namespace ui {
-
-namespace {
-
-const char kAtomPair[] = "ATOM_PAIR";
-const char kIncr[] = "INCR";
-const char kMultiple[] = "MULTIPLE";
-const char kSaveTargets[] = "SAVE_TARGETS";
-const char kTargets[] = "TARGETS";
-
-const char* kAtomsToCache[] = {
- kAtomPair,
- kIncr,
- kMultiple,
- kSaveTargets,
- kTargets,
- NULL
-};
-
-// The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <=
-// than kIncrementalTransferTimeoutMs.
-const int kTimerPeriodMs = 1000;
-
-// The amount of time to wait for the selection requestor to process the data
-// sent by the selection owner before aborting an incremental data transfer.
-const int kIncrementalTransferTimeoutMs = 10000;
-
-COMPILE_ASSERT(kTimerPeriodMs <= kIncrementalTransferTimeoutMs,
- timer_period_must_be_less_or_equal_to_transfer_timeout);
-
-// 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);
- long max_size =
- (extended_max_size ? extended_max_size : XMaxRequestSize(display)) - 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 = None;
- int format = 0; // size in bits of each item in 'property'
- unsigned long num_items = 0;
- unsigned char* properties = NULL;
- unsigned long remaining_bytes = 0;
-
- int result = XGetWindowProperty(gfx::GetXDisplay(),
- window,
- property,
- 0, // offset into property data to
- // read
- (~0L), // entire array
- False, // deleted
- AnyPropertyType,
- &type,
- &format,
- &num_items,
- &remaining_bytes,
- &properties);
-
- if (result != Success)
- return false;
-
- // GTK does not require |type| to be kAtomPair.
- if (format != 32 || num_items % 2 != 0) {
- XFree(properties);
- 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]));
- XFree(properties);
- return true;
-}
-
-} // namespace
-
-SelectionOwner::SelectionOwner(XDisplay* x_display,
- XID x_window,
- XAtom selection_name)
- : x_display_(x_display),
- x_window_(x_window),
- selection_name_(selection_name),
- max_request_size_(GetMaxRequestSize(x_display)),
- atom_cache_(x_display_, kAtomsToCache) {
-}
-
-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_, None, CurrentTime);
-}
-
-void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) {
- for (SelectionFormatMap::const_iterator it = format_map_.begin();
- it != format_map_.end(); ++it) {
- targets->push_back(it->first);
- }
-}
-
-void SelectionOwner::TakeOwnershipOfSelection(
- const SelectionFormatMap& data) {
- XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime);
-
- if (XGetSelectionOwner(x_display_, 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_, None, CurrentTime);
- 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;
-
- // 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 = None; // Indicates failure
- reply.xselection.time = event.xselectionrequest.time;
-
- if (requested_target == atom_cache_.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 (size_t i = 0; i < conversions.size(); ++i) {
- bool conversion_successful = ProcessTarget(conversions[i].first,
- requestor,
- conversions[i].second);
- conversion_results.push_back(conversions[i].first);
- conversion_results.push_back(
- conversion_successful ? conversions[i].second : None);
- }
-
- // Set the property to indicate which conversions succeeded. This matches
- // what GTK does.
- XChangeProperty(
- x_display_,
- requestor,
- requested_property,
- atom_cache_.GetAtom(kAtomPair),
- 32,
- PropModeReplace,
- reinterpret_cast<const unsigned char*>(&conversion_results.front()),
- conversion_results.size());
-
- reply.xselection.property = requested_property;
- }
- } else {
- if (ProcessTarget(requested_target, requestor, requested_property))
- reply.xselection.property = requested_property;
- }
-
- // Send off the reply.
- XSendEvent(x_display_, requestor, False, 0, &reply);
-}
-
-void SelectionOwner::OnSelectionClear(const XEvent& 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 &&
- FindIncrementalTransferForEvent(event) != incremental_transfers_.end();
-}
-
-void SelectionOwner::OnPropertyEvent(const XEvent& event) {
- std::vector<IncrementalTransfer>::iterator it =
- FindIncrementalTransferForEvent(event);
- if (it == incremental_transfers_.end())
- return;
-
- ProcessIncrementalTransfer(&(*it));
- if (!it->data.get())
- CompleteIncrementalTransfer(it);
-}
-
-bool SelectionOwner::ProcessTarget(XAtom target,
- XID requestor,
- XAtom property) {
- XAtom multiple_atom = atom_cache_.GetAtom(kMultiple);
- XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets);
- XAtom targets_atom = atom_cache_.GetAtom(kTargets);
-
- if (target == multiple_atom || target == save_targets_atom)
- return false;
-
- 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;
- targets.push_back(targets_atom);
- targets.push_back(save_targets_atom);
- targets.push_back(multiple_atom);
- RetrieveTargets(&targets);
-
- XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&targets.front()),
- targets.size());
- return true;
- } else {
- // Try to find the data type in map.
- SelectionFormatMap::const_iterator it = format_map_.find(target);
- if (it != format_map_.end()) {
- if (it->second->size() > max_request_size_) {
- // 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".
- int length = it->second->size();
- XChangeProperty(x_display_,
- requestor,
- property,
- atom_cache_.GetAtom(kIncr),
- 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&length),
- 1);
-
- // Wait for the selection requestor to indicate that it has processed
- // the selection result before sending the first chunk of data. The
- // selection requestor indicates this by deleting |property|.
- base::TimeTicks timeout =
- base::TimeTicks::Now() +
- base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
- int foreign_window_manager_id =
- ui::XForeignWindowManager::GetInstance()->RequestEvents(
- requestor, PropertyChangeMask);
- incremental_transfers_.push_back(
- IncrementalTransfer(requestor,
- target,
- property,
- it->second,
- 0,
- timeout,
- foreign_window_manager_id));
-
- // Start a timer to abort the data transfer in case that the selection
- // requestor does not support the INCR property or gets destroyed during
- // the data transfer.
- if (!incremental_transfer_abort_timer_.IsRunning()) {
- incremental_transfer_abort_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kTimerPeriodMs),
- this,
- &SelectionOwner::AbortStaleIncrementalTransfers);
- }
- } else {
- XChangeProperty(
- x_display_,
- requestor,
- property,
- target,
- 8,
- PropModeReplace,
- const_cast<unsigned char*>(it->second->front()),
- it->second->size());
- }
- return true;
- }
- // I would put error logging here, but GTK ignores TARGETS and spams us
- // looking for its own internal types.
- }
- return false;
-}
-
-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);
- transfer->offset += chunk_length;
- transfer->timeout = base::TimeTicks::Now() +
- base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
-
- // When offset == data->size(), we still need to transfer a zero-sized chunk
- // to notify the selection requestor that the transfer is complete. Clear
- // transfer->data once the zero-sized chunk is sent to indicate that state
- // related to this data transfer can be cleared.
- if (chunk_length == 0)
- transfer->data = NULL;
-}
-
-void SelectionOwner::AbortStaleIncrementalTransfers() {
- base::TimeTicks now = base::TimeTicks::Now();
- for (int i = static_cast<int>(incremental_transfers_.size()) - 1;
- i >= 0; --i) {
- if (incremental_transfers_[i].timeout <= now)
- CompleteIncrementalTransfer(incremental_transfers_.begin() + i);
- }
-}
-
-void SelectionOwner::CompleteIncrementalTransfer(
- std::vector<IncrementalTransfer>::iterator it) {
- ui::XForeignWindowManager::GetInstance()->CancelRequest(
- it->foreign_window_manager_id);
- incremental_transfers_.erase(it);
-
- if (incremental_transfers_.empty())
- incremental_transfer_abort_timer_.Stop();
-}
-
-std::vector<SelectionOwner::IncrementalTransfer>::iterator
- SelectionOwner::FindIncrementalTransferForEvent(const XEvent& event) {
- for (std::vector<IncrementalTransfer>::iterator it =
- incremental_transfers_.begin();
- it != incremental_transfers_.end();
- ++it) {
- if (it->window == event.xproperty.window &&
- it->property == event.xproperty.atom) {
- return it;
- }
- }
- return incremental_transfers_.end();
-}
-
-SelectionOwner::IncrementalTransfer::IncrementalTransfer(
- XID window,
- XAtom target,
- XAtom property,
- const scoped_refptr<base::RefCountedMemory>& data,
- int offset,
- base::TimeTicks timeout,
- int foreign_window_manager_id)
- : window(window),
- target(target),
- property(property),
- data(data),
- offset(offset),
- timeout(timeout),
- foreign_window_manager_id(foreign_window_manager_id) {
-}
-
-SelectionOwner::IncrementalTransfer::~IncrementalTransfer() {
-}
-
-} // namespace ui
« no previous file with comments | « ui/base/x/selection_owner.h ('k') | ui/base/x/selection_requestor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698