Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/base/x/selection_owner.h" | 5 #include "ui/base/x/selection_owner.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "ui/base/x/selection_utils.h" | 12 #include "ui/base/x/selection_utils.h" |
| 13 #include "ui/base/x/x11_foreign_window_manager.h" | 13 #include "ui/base/x/x11_foreign_window_manager.h" |
| 14 #include "ui/base/x/x11_util.h" | 14 #include "ui/base/x/x11_util.h" |
| 15 | 15 |
| 16 namespace ui { | 16 namespace ui { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 const char kAtomPair[] = "ATOM_PAIR"; | 20 const char kAtomPair[] = "ATOM_PAIR"; |
| 21 const char kIncr[] = "INCR"; | 21 const char kIncr[] = "INCR"; |
| 22 const char kMultiple[] = "MULTIPLE"; | 22 const char kMultiple[] = "MULTIPLE"; |
| 23 const char kSaveTargets[] = "SAVE_TARGETS"; | 23 const char kSaveTargets[] = "SAVE_TARGETS"; |
| 24 const char kTargets[] = "TARGETS"; | 24 const char kTargets[] = "TARGETS"; |
| 25 const char kTimestamp[] = "TIMESTAMP"; | |
| 25 | 26 |
| 26 const char* kAtomsToCache[] = { | 27 // Used in conjunction with GetCurrentTimeFromX. |
| 27 kAtomPair, | 28 const char kDummyTimestampProperty[] = "CHROMIUM_TIMESTAMP_PROPERTY"; |
| 28 kIncr, | 29 |
| 29 kMultiple, | 30 const char* kAtomsToCache[] = {kAtomPair, |
| 30 kSaveTargets, | 31 kIncr, |
| 31 kTargets, | 32 kMultiple, |
| 32 NULL | 33 kSaveTargets, |
| 33 }; | 34 kTargets, |
| 35 kTimestamp, | |
| 36 kDummyTimestampProperty, | |
| 37 NULL}; | |
| 34 | 38 |
| 35 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= | 39 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= |
| 36 // than kIncrementalTransferTimeoutMs. | 40 // than kIncrementalTransferTimeoutMs. |
| 37 const int kTimerPeriodMs = 1000; | 41 const int kTimerPeriodMs = 1000; |
| 38 | 42 |
| 39 // The amount of time to wait for the selection requestor to process the data | 43 // The amount of time to wait for the selection requestor to process the data |
| 40 // sent by the selection owner before aborting an incremental data transfer. | 44 // sent by the selection owner before aborting an incremental data transfer. |
| 41 const int kIncrementalTransferTimeoutMs = 10000; | 45 const int kIncrementalTransferTimeoutMs = 10000; |
| 42 | 46 |
| 43 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs, | 47 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs, |
| 44 "timer period must be <= transfer timeout"); | 48 "timer period must be <= transfer timeout"); |
| 45 | 49 |
| 46 // Returns a conservative max size of the data we can pass into | 50 // Returns a conservative max size of the data we can pass into |
| 47 // XChangeProperty(). Copied from GTK. | 51 // XChangeProperty(). Copied from GTK. |
| 48 size_t GetMaxRequestSize(XDisplay* display) { | 52 size_t GetMaxRequestSize(XDisplay* display) { |
| 49 long extended_max_size = XExtendedMaxRequestSize(display); | 53 long extended_max_size = XExtendedMaxRequestSize(display); |
| 50 long max_size = | 54 long max_size = |
| 51 (extended_max_size ? extended_max_size : XMaxRequestSize(display)) - 100; | 55 (extended_max_size ? extended_max_size : XMaxRequestSize(display)) - 100; |
| 52 return std::min(static_cast<long>(0x40000), | 56 return std::min(static_cast<long>(0x40000), |
| 53 std::max(static_cast<long>(0), max_size)); | 57 std::max(static_cast<long>(0), max_size)); |
| 54 } | 58 } |
| 55 | 59 |
| 60 // Get the value of CurrentTime from X. There's no easy way to do this, so like | |
| 61 // GTK, we do this by triggering a spurious property change and inspecting the | |
| 62 // resulting event. | |
| 63 Time GetCurrentTimeFromX(XDisplay* display, XID window, XAtom property) { | |
| 64 unsigned char c = 0; | |
| 65 XChangeProperty(display, window, property, property, 8, PropModeReplace, &c, | |
| 66 1); | |
| 67 struct ArgData { | |
| 68 // Target window and atom to wait for. | |
| 69 XID window; | |
| 70 XAtom atom; | |
| 71 } args = {window, property}; | |
| 72 auto predicate = [](XDisplay* display, XEvent* event, XPointer arg) -> Bool { | |
| 73 ArgData* data = reinterpret_cast<ArgData*>(arg); | |
| 74 return (event->type == PropertyNotify && | |
| 75 event->xproperty.window == data->window && | |
| 76 event->xproperty.atom == data->atom) | |
| 77 ? True | |
| 78 : False; | |
| 79 | |
| 80 }; | |
| 81 XEvent event; | |
| 82 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
| |
| 83 return event.xproperty.time; | |
| 84 } | |
| 85 | |
| 56 // Gets the value of an atom pair array property. On success, true is returned | 86 // Gets the value of an atom pair array property. On success, true is returned |
| 57 // and the value is stored in |value|. | 87 // and the value is stored in |value|. |
| 58 bool GetAtomPairArrayProperty(XID window, | 88 bool GetAtomPairArrayProperty(XID window, |
| 59 XAtom property, | 89 XAtom property, |
| 60 std::vector<std::pair<XAtom,XAtom> >* value) { | 90 std::vector<std::pair<XAtom,XAtom> >* value) { |
| 61 XAtom type = None; | 91 XAtom type = None; |
| 62 int format = 0; // size in bits of each item in 'property' | 92 int format = 0; // size in bits of each item in 'property' |
| 63 unsigned long num_items = 0; | 93 unsigned long num_items = 0; |
| 64 unsigned char* properties = NULL; | 94 unsigned char* properties = NULL; |
| 65 unsigned long remaining_bytes = 0; | 95 unsigned long remaining_bytes = 0; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 | 145 |
| 116 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { | 146 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { |
| 117 for (SelectionFormatMap::const_iterator it = format_map_.begin(); | 147 for (SelectionFormatMap::const_iterator it = format_map_.begin(); |
| 118 it != format_map_.end(); ++it) { | 148 it != format_map_.end(); ++it) { |
| 119 targets->push_back(it->first); | 149 targets->push_back(it->first); |
| 120 } | 150 } |
| 121 } | 151 } |
| 122 | 152 |
| 123 void SelectionOwner::TakeOwnershipOfSelection( | 153 void SelectionOwner::TakeOwnershipOfSelection( |
| 124 const SelectionFormatMap& data) { | 154 const SelectionFormatMap& data) { |
| 125 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); | 155 // Note that we don't just use CurrentTime, since we need to return an actual |
| 156 // timestamp for the TIMESTAMP target later. | |
| 157 acquired_selection_timestamp_ = GetCurrentTimeFromX( | |
| 158 x_display_, x_window_, atom_cache_.GetAtom(kDummyTimestampProperty)); | |
| 159 XSetSelectionOwner(x_display_, selection_name_, x_window_, | |
| 160 acquired_selection_timestamp_); | |
| 126 | 161 |
| 127 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { | 162 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { |
| 128 // The X server agrees that we are the selection owner. Commit our data. | 163 // The X server agrees that we are the selection owner. Commit our data. |
| 129 format_map_ = data; | 164 format_map_ = data; |
| 130 } | 165 } |
| 131 } | 166 } |
| 132 | 167 |
| 133 void SelectionOwner::ClearSelectionOwner() { | 168 void SelectionOwner::ClearSelectionOwner() { |
| 134 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); | 169 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); |
| 135 format_map_ = SelectionFormatMap(); | 170 format_map_ = SelectionFormatMap(); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 if (!it->data.get()) | 247 if (!it->data.get()) |
| 213 CompleteIncrementalTransfer(it); | 248 CompleteIncrementalTransfer(it); |
| 214 } | 249 } |
| 215 | 250 |
| 216 bool SelectionOwner::ProcessTarget(XAtom target, | 251 bool SelectionOwner::ProcessTarget(XAtom target, |
| 217 XID requestor, | 252 XID requestor, |
| 218 XAtom property) { | 253 XAtom property) { |
| 219 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); | 254 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); |
| 220 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); | 255 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); |
| 221 XAtom targets_atom = atom_cache_.GetAtom(kTargets); | 256 XAtom targets_atom = atom_cache_.GetAtom(kTargets); |
| 257 XAtom timestamp_atom = atom_cache_.GetAtom(kTimestamp); | |
| 222 | 258 |
| 223 if (target == multiple_atom || target == save_targets_atom) | 259 if (target == multiple_atom || target == save_targets_atom) |
| 224 return false; | 260 return false; |
| 225 | 261 |
| 226 if (target == targets_atom) { | 262 if (target == timestamp_atom) { |
| 263 XChangeProperty( | |
| 264 x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace, | |
| 265 reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1); | |
| 266 return true; | |
| 267 } else if (target == targets_atom) { | |
| 227 // We have been asked for TARGETS. Send an atom array back with the data | 268 // We have been asked for TARGETS. Send an atom array back with the data |
| 228 // types we support. | 269 // types we support. |
| 229 std::vector<XAtom> targets; | 270 std::vector<XAtom> targets; |
| 271 targets.push_back(timestamp_atom); | |
| 230 targets.push_back(targets_atom); | 272 targets.push_back(targets_atom); |
| 231 targets.push_back(save_targets_atom); | 273 targets.push_back(save_targets_atom); |
| 232 targets.push_back(multiple_atom); | 274 targets.push_back(multiple_atom); |
| 233 RetrieveTargets(&targets); | 275 RetrieveTargets(&targets); |
| 234 | 276 |
| 235 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, | 277 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, |
| 236 PropModeReplace, | 278 PropModeReplace, |
| 237 reinterpret_cast<unsigned char*>(&targets.front()), | 279 reinterpret_cast<unsigned char*>(&targets.front()), |
| 238 targets.size()); | 280 targets.size()); |
| 239 return true; | 281 return true; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 foreign_window_manager_id(foreign_window_manager_id) { | 418 foreign_window_manager_id(foreign_window_manager_id) { |
| 377 } | 419 } |
| 378 | 420 |
| 379 SelectionOwner::IncrementalTransfer::IncrementalTransfer( | 421 SelectionOwner::IncrementalTransfer::IncrementalTransfer( |
| 380 const IncrementalTransfer& other) = default; | 422 const IncrementalTransfer& other) = default; |
| 381 | 423 |
| 382 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { | 424 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { |
| 383 } | 425 } |
| 384 | 426 |
| 385 } // namespace ui | 427 } // namespace ui |
| OLD | NEW |