Index: ui/base/x/selection_owner.cc |
diff --git a/ui/base/x/selection_owner.cc b/ui/base/x/selection_owner.cc |
index 170f32e19b2c0ea71e90bdb53e9386c5aea26fb0..97b128be5ddfa3e8c1f4537294610fee8bd12d97 100644 |
--- a/ui/base/x/selection_owner.cc |
+++ b/ui/base/x/selection_owner.cc |
@@ -22,15 +22,19 @@ const char kIncr[] = "INCR"; |
const char kMultiple[] = "MULTIPLE"; |
const char kSaveTargets[] = "SAVE_TARGETS"; |
const char kTargets[] = "TARGETS"; |
+const char kTimestamp[] = "TIMESTAMP"; |
-const char* kAtomsToCache[] = { |
- kAtomPair, |
- kIncr, |
- kMultiple, |
- kSaveTargets, |
- kTargets, |
- NULL |
-}; |
+// Used in conjunction with GetCurrentTimeFromX. |
+const char kDummyTimestampProperty[] = "CHROMIUM_TIMESTAMP_PROPERTY"; |
+ |
+const char* kAtomsToCache[] = {kAtomPair, |
+ kIncr, |
+ kMultiple, |
+ kSaveTargets, |
+ kTargets, |
+ kTimestamp, |
+ kDummyTimestampProperty, |
+ NULL}; |
// The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= |
// than kIncrementalTransferTimeoutMs. |
@@ -53,6 +57,32 @@ size_t GetMaxRequestSize(XDisplay* display) { |
std::max(static_cast<long>(0), max_size)); |
} |
+// Get the value of CurrentTime from X. There's no easy way to do this, so like |
+// GTK, we do this by triggering a spurious property change and inspecting the |
+// resulting event. |
+Time GetCurrentTimeFromX(XDisplay* display, XID window, XAtom property) { |
+ unsigned char c = 0; |
+ XChangeProperty(display, window, property, property, 8, PropModeReplace, &c, |
+ 1); |
+ struct ArgData { |
+ // Target window and atom to wait for. |
+ XID window; |
+ XAtom atom; |
+ } args = {window, property}; |
+ auto predicate = [](XDisplay* display, XEvent* event, XPointer arg) -> Bool { |
+ ArgData* data = reinterpret_cast<ArgData*>(arg); |
+ return (event->type == PropertyNotify && |
+ event->xproperty.window == data->window && |
+ event->xproperty.atom == data->atom) |
+ ? True |
+ : False; |
+ |
+ }; |
+ XEvent event; |
+ XIfEvent(display, &event, +predicate, reinterpret_cast<XPointer>(&args)); |
Elliot Glaysher
2016/04/15 21:45:31
"+" predicate? I assume the unary plus is some sor
dcheng
2016/04/15 21:53:47
I was forcing a decay to function pointer, but it
|
+ return event.xproperty.time; |
+} |
+ |
// 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, |
@@ -122,7 +152,12 @@ void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { |
void SelectionOwner::TakeOwnershipOfSelection( |
const SelectionFormatMap& data) { |
- XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); |
+ // Note that we don't just use CurrentTime, since we need to return an actual |
+ // timestamp for the TIMESTAMP target later. |
+ acquired_selection_timestamp_ = GetCurrentTimeFromX( |
+ x_display_, x_window_, atom_cache_.GetAtom(kDummyTimestampProperty)); |
+ XSetSelectionOwner(x_display_, selection_name_, x_window_, |
+ acquired_selection_timestamp_); |
if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { |
// The X server agrees that we are the selection owner. Commit our data. |
@@ -219,14 +254,21 @@ bool SelectionOwner::ProcessTarget(XAtom target, |
XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); |
XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); |
XAtom targets_atom = atom_cache_.GetAtom(kTargets); |
+ XAtom timestamp_atom = atom_cache_.GetAtom(kTimestamp); |
if (target == multiple_atom || target == save_targets_atom) |
return false; |
- if (target == targets_atom) { |
+ if (target == timestamp_atom) { |
+ XChangeProperty( |
+ x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace, |
+ reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1); |
+ return true; |
+ } else 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(timestamp_atom); |
targets.push_back(targets_atom); |
targets.push_back(save_targets_atom); |
targets.push_back(multiple_atom); |