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)); | |
83 return event.xproperty.time; | |
sadrul
2016/04/19 16:11:52
How does things break when we use CurrentTime?
We
dcheng
2016/04/19 17:24:15
Just using CurrentTime is unlikely to actually res
Elliot Glaysher
2016/04/19 17:30:36
Sadly, I wouldn't rely on that. We currently have
dcheng
2016/04/19 17:44:11
Is the concern here that some other app will XChan
| |
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 |