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 "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "ui/base/x/selection_utils.h" | 13 #include "ui/base/x/selection_utils.h" |
14 #include "ui/base/x/x11_util.h" | 14 #include "ui/base/x/x11_util.h" |
15 #include "ui/base/x/x11_window_event_manager.h" | 15 #include "ui/base/x/x11_window_event_manager.h" |
16 #include "ui/events/platform/x11/x11_event_source.h" | 16 #include "ui/events/platform/x11/x11_event_source.h" |
17 | 17 |
18 namespace ui { | 18 namespace ui { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 const char kAtomPair[] = "ATOM_PAIR"; | 22 const char kAtomPair[] = "ATOM_PAIR"; |
23 const char kIncr[] = "INCR"; | 23 const char kIncr[] = "INCR"; |
24 const char kMultiple[] = "MULTIPLE"; | 24 const char kMultiple[] = "MULTIPLE"; |
25 const char kSaveTargets[] = "SAVE_TARGETS"; | 25 const char kSaveTargets[] = "SAVE_TARGETS"; |
26 const char kTargets[] = "TARGETS"; | 26 const char kTargets[] = "TARGETS"; |
27 const char kTimestamp[] = "TIMESTAMP"; | 27 const char kTimestamp[] = "TIMESTAMP"; |
28 | 28 |
29 const char* kAtomsToCache[] = {kAtomPair, kIncr, kMultiple, kSaveTargets, | |
30 kTargets, kTimestamp, NULL}; | |
31 | |
32 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= | 29 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= |
33 // than kIncrementalTransferTimeoutMs. | 30 // than kIncrementalTransferTimeoutMs. |
34 const int kTimerPeriodMs = 1000; | 31 const int kTimerPeriodMs = 1000; |
35 | 32 |
36 // The amount of time to wait for the selection requestor to process the data | 33 // The amount of time to wait for the selection requestor to process the data |
37 // sent by the selection owner before aborting an incremental data transfer. | 34 // sent by the selection owner before aborting an incremental data transfer. |
38 const int kIncrementalTransferTimeoutMs = 10000; | 35 const int kIncrementalTransferTimeoutMs = 10000; |
39 | 36 |
40 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs, | 37 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs, |
41 "timer period must be <= transfer timeout"); | 38 "timer period must be <= transfer timeout"); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 } | 88 } |
92 | 89 |
93 } // namespace | 90 } // namespace |
94 | 91 |
95 SelectionOwner::SelectionOwner(XDisplay* x_display, | 92 SelectionOwner::SelectionOwner(XDisplay* x_display, |
96 XID x_window, | 93 XID x_window, |
97 XAtom selection_name) | 94 XAtom selection_name) |
98 : x_display_(x_display), | 95 : x_display_(x_display), |
99 x_window_(x_window), | 96 x_window_(x_window), |
100 selection_name_(selection_name), | 97 selection_name_(selection_name), |
101 max_request_size_(GetMaxRequestSize(x_display)), | 98 max_request_size_(GetMaxRequestSize(x_display)) {} |
102 atom_cache_(x_display_, kAtomsToCache) { | |
103 } | |
104 | 99 |
105 SelectionOwner::~SelectionOwner() { | 100 SelectionOwner::~SelectionOwner() { |
106 // If we are the selection owner, we need to release the selection so we | 101 // If we are the selection owner, we need to release the selection so we |
107 // don't receive further events. However, we don't call ClearSelectionOwner() | 102 // don't receive further events. However, we don't call ClearSelectionOwner() |
108 // because we don't want to do this indiscriminately. | 103 // because we don't want to do this indiscriminately. |
109 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) | 104 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) |
110 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); | 105 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); |
111 } | 106 } |
112 | 107 |
113 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { | 108 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { |
(...skipping 28 matching lines...) Expand all Loading... |
142 // Incrementally build our selection. By default this is a refusal, and we'll | 137 // Incrementally build our selection. By default this is a refusal, and we'll |
143 // override the parts indicating success in the different cases. | 138 // override the parts indicating success in the different cases. |
144 XEvent reply; | 139 XEvent reply; |
145 reply.xselection.type = SelectionNotify; | 140 reply.xselection.type = SelectionNotify; |
146 reply.xselection.requestor = requestor; | 141 reply.xselection.requestor = requestor; |
147 reply.xselection.selection = event.xselectionrequest.selection; | 142 reply.xselection.selection = event.xselectionrequest.selection; |
148 reply.xselection.target = requested_target; | 143 reply.xselection.target = requested_target; |
149 reply.xselection.property = None; // Indicates failure | 144 reply.xselection.property = None; // Indicates failure |
150 reply.xselection.time = event.xselectionrequest.time; | 145 reply.xselection.time = event.xselectionrequest.time; |
151 | 146 |
152 if (requested_target == atom_cache_.GetAtom(kMultiple)) { | 147 if (requested_target == GetAtom(kMultiple)) { |
153 // The contents of |requested_property| should be a list of | 148 // The contents of |requested_property| should be a list of |
154 // <target,property> pairs. | 149 // <target,property> pairs. |
155 std::vector<std::pair<XAtom,XAtom> > conversions; | 150 std::vector<std::pair<XAtom,XAtom> > conversions; |
156 if (GetAtomPairArrayProperty(requestor, | 151 if (GetAtomPairArrayProperty(requestor, |
157 requested_property, | 152 requested_property, |
158 &conversions)) { | 153 &conversions)) { |
159 std::vector<XAtom> conversion_results; | 154 std::vector<XAtom> conversion_results; |
160 for (size_t i = 0; i < conversions.size(); ++i) { | 155 for (size_t i = 0; i < conversions.size(); ++i) { |
161 bool conversion_successful = ProcessTarget(conversions[i].first, | 156 bool conversion_successful = ProcessTarget(conversions[i].first, |
162 requestor, | 157 requestor, |
163 conversions[i].second); | 158 conversions[i].second); |
164 conversion_results.push_back(conversions[i].first); | 159 conversion_results.push_back(conversions[i].first); |
165 conversion_results.push_back( | 160 conversion_results.push_back( |
166 conversion_successful ? conversions[i].second : None); | 161 conversion_successful ? conversions[i].second : None); |
167 } | 162 } |
168 | 163 |
169 // Set the property to indicate which conversions succeeded. This matches | 164 // Set the property to indicate which conversions succeeded. This matches |
170 // what GTK does. | 165 // what GTK does. |
171 XChangeProperty( | 166 XChangeProperty( |
172 x_display_, | 167 x_display_, requestor, requested_property, GetAtom(kAtomPair), 32, |
173 requestor, | |
174 requested_property, | |
175 atom_cache_.GetAtom(kAtomPair), | |
176 32, | |
177 PropModeReplace, | 168 PropModeReplace, |
178 reinterpret_cast<const unsigned char*>(&conversion_results.front()), | 169 reinterpret_cast<const unsigned char*>(&conversion_results.front()), |
179 conversion_results.size()); | 170 conversion_results.size()); |
180 | 171 |
181 reply.xselection.property = requested_property; | 172 reply.xselection.property = requested_property; |
182 } | 173 } |
183 } else { | 174 } else { |
184 if (ProcessTarget(requested_target, requestor, requested_property)) | 175 if (ProcessTarget(requested_target, requestor, requested_property)) |
185 reply.xselection.property = requested_property; | 176 reply.xselection.property = requested_property; |
186 } | 177 } |
(...skipping 21 matching lines...) Expand all Loading... |
208 return; | 199 return; |
209 | 200 |
210 ProcessIncrementalTransfer(&(*it)); | 201 ProcessIncrementalTransfer(&(*it)); |
211 if (!it->data.get()) | 202 if (!it->data.get()) |
212 CompleteIncrementalTransfer(it); | 203 CompleteIncrementalTransfer(it); |
213 } | 204 } |
214 | 205 |
215 bool SelectionOwner::ProcessTarget(XAtom target, | 206 bool SelectionOwner::ProcessTarget(XAtom target, |
216 XID requestor, | 207 XID requestor, |
217 XAtom property) { | 208 XAtom property) { |
218 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); | 209 XAtom multiple_atom = GetAtom(kMultiple); |
219 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); | 210 XAtom save_targets_atom = GetAtom(kSaveTargets); |
220 XAtom targets_atom = atom_cache_.GetAtom(kTargets); | 211 XAtom targets_atom = GetAtom(kTargets); |
221 XAtom timestamp_atom = atom_cache_.GetAtom(kTimestamp); | 212 XAtom timestamp_atom = GetAtom(kTimestamp); |
222 | 213 |
223 if (target == multiple_atom || target == save_targets_atom) | 214 if (target == multiple_atom || target == save_targets_atom) |
224 return false; | 215 return false; |
225 | 216 |
226 if (target == timestamp_atom) { | 217 if (target == timestamp_atom) { |
227 XChangeProperty( | 218 XChangeProperty( |
228 x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace, | 219 x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace, |
229 reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1); | 220 reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1); |
230 return true; | 221 return true; |
231 } | 222 } |
(...skipping 16 matching lines...) Expand all Loading... |
248 } | 239 } |
249 | 240 |
250 // Try to find the data type in map. | 241 // Try to find the data type in map. |
251 SelectionFormatMap::const_iterator it = format_map_.find(target); | 242 SelectionFormatMap::const_iterator it = format_map_.find(target); |
252 if (it != format_map_.end()) { | 243 if (it != format_map_.end()) { |
253 if (it->second->size() > max_request_size_) { | 244 if (it->second->size() > max_request_size_) { |
254 // We must send the data back in several chunks due to a limitation in | 245 // We must send the data back in several chunks due to a limitation in |
255 // the size of X requests. Notify the selection requestor that the data | 246 // the size of X requests. Notify the selection requestor that the data |
256 // will be sent incrementally by returning data of type "INCR". | 247 // will be sent incrementally by returning data of type "INCR". |
257 long length = it->second->size(); | 248 long length = it->second->size(); |
258 XChangeProperty(x_display_, | 249 XChangeProperty(x_display_, requestor, property, GetAtom(kIncr), 32, |
259 requestor, | |
260 property, | |
261 atom_cache_.GetAtom(kIncr), | |
262 32, | |
263 PropModeReplace, | 250 PropModeReplace, |
264 reinterpret_cast<unsigned char*>(&length), | 251 reinterpret_cast<unsigned char*>(&length), 1); |
265 1); | |
266 | 252 |
267 // Wait for the selection requestor to indicate that it has processed | 253 // Wait for the selection requestor to indicate that it has processed |
268 // the selection result before sending the first chunk of data. The | 254 // the selection result before sending the first chunk of data. The |
269 // selection requestor indicates this by deleting |property|. | 255 // selection requestor indicates this by deleting |property|. |
270 base::TimeTicks timeout = | 256 base::TimeTicks timeout = |
271 base::TimeTicks::Now() + | 257 base::TimeTicks::Now() + |
272 base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs); | 258 base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs); |
273 incremental_transfers_.push_back(IncrementalTransfer( | 259 incremental_transfers_.push_back(IncrementalTransfer( |
274 requestor, target, property, | 260 requestor, target, property, |
275 base::MakeUnique<XScopedEventSelector>(requestor, PropertyChangeMask), | 261 base::MakeUnique<XScopedEventSelector>(requestor, PropertyChangeMask), |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 SelectionOwner::IncrementalTransfer::IncrementalTransfer( | 364 SelectionOwner::IncrementalTransfer::IncrementalTransfer( |
379 IncrementalTransfer&& other) = default; | 365 IncrementalTransfer&& other) = default; |
380 | 366 |
381 SelectionOwner::IncrementalTransfer& SelectionOwner::IncrementalTransfer:: | 367 SelectionOwner::IncrementalTransfer& SelectionOwner::IncrementalTransfer:: |
382 operator=(IncrementalTransfer&&) = default; | 368 operator=(IncrementalTransfer&&) = default; |
383 | 369 |
384 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { | 370 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { |
385 } | 371 } |
386 | 372 |
387 } // namespace ui | 373 } // namespace ui |
OLD | NEW |