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

Side by Side Diff: ui/base/x/selection_owner.cc

Issue 1892483005: SelectionOwner: add support for TIMESTAMP target (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: USE_GLIB Created 4 years, 8 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 unified diff | Download patch
« no previous file with comments | « ui/base/x/selection_owner.h ('k') | ui/events/platform/x11/x11_event_source.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "ui/events/platform/x11/x11_event_source.h"
15 16
16 namespace ui { 17 namespace ui {
17 18
18 namespace { 19 namespace {
19 20
20 const char kAtomPair[] = "ATOM_PAIR"; 21 const char kAtomPair[] = "ATOM_PAIR";
21 const char kIncr[] = "INCR"; 22 const char kIncr[] = "INCR";
22 const char kMultiple[] = "MULTIPLE"; 23 const char kMultiple[] = "MULTIPLE";
23 const char kSaveTargets[] = "SAVE_TARGETS"; 24 const char kSaveTargets[] = "SAVE_TARGETS";
24 const char kTargets[] = "TARGETS"; 25 const char kTargets[] = "TARGETS";
26 const char kTimestamp[] = "TIMESTAMP";
25 27
26 const char* kAtomsToCache[] = { 28 const char* kAtomsToCache[] = {kAtomPair, kIncr, kMultiple, kSaveTargets,
27 kAtomPair, 29 kTargets, kTimestamp, NULL};
28 kIncr,
29 kMultiple,
30 kSaveTargets,
31 kTargets,
32 NULL
33 };
34 30
35 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <= 31 // The period of |incremental_transfer_abort_timer_|. Arbitrary but must be <=
36 // than kIncrementalTransferTimeoutMs. 32 // than kIncrementalTransferTimeoutMs.
37 const int kTimerPeriodMs = 1000; 33 const int kTimerPeriodMs = 1000;
38 34
39 // The amount of time to wait for the selection requestor to process the data 35 // 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. 36 // sent by the selection owner before aborting an incremental data transfer.
41 const int kIncrementalTransferTimeoutMs = 10000; 37 const int kIncrementalTransferTimeoutMs = 10000;
42 38
43 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs, 39 static_assert(kTimerPeriodMs <= kIncrementalTransferTimeoutMs,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 111
116 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { 112 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) {
117 for (SelectionFormatMap::const_iterator it = format_map_.begin(); 113 for (SelectionFormatMap::const_iterator it = format_map_.begin();
118 it != format_map_.end(); ++it) { 114 it != format_map_.end(); ++it) {
119 targets->push_back(it->first); 115 targets->push_back(it->first);
120 } 116 }
121 } 117 }
122 118
123 void SelectionOwner::TakeOwnershipOfSelection( 119 void SelectionOwner::TakeOwnershipOfSelection(
124 const SelectionFormatMap& data) { 120 const SelectionFormatMap& data) {
121 // Save the last server timestamp seen from X, to satisfy requests for the
122 // TIMESTAMP target later…
123 acquired_selection_timestamp_ =
124 X11EventSource::GetInstance()->last_seen_server_time();
125 // …but always pass CurrentTime to XSetSelectionOwner to increase the chances
126 // of this succeeding.
125 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); 127 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime);
126 128
127 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { 129 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) {
128 // The X server agrees that we are the selection owner. Commit our data. 130 // The X server agrees that we are the selection owner. Commit our data.
129 format_map_ = data; 131 format_map_ = data;
130 } 132 }
131 } 133 }
132 134
133 void SelectionOwner::ClearSelectionOwner() { 135 void SelectionOwner::ClearSelectionOwner() {
134 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); 136 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 if (!it->data.get()) 214 if (!it->data.get())
213 CompleteIncrementalTransfer(it); 215 CompleteIncrementalTransfer(it);
214 } 216 }
215 217
216 bool SelectionOwner::ProcessTarget(XAtom target, 218 bool SelectionOwner::ProcessTarget(XAtom target,
217 XID requestor, 219 XID requestor,
218 XAtom property) { 220 XAtom property) {
219 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); 221 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple);
220 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); 222 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets);
221 XAtom targets_atom = atom_cache_.GetAtom(kTargets); 223 XAtom targets_atom = atom_cache_.GetAtom(kTargets);
224 XAtom timestamp_atom = atom_cache_.GetAtom(kTimestamp);
222 225
223 if (target == multiple_atom || target == save_targets_atom) 226 if (target == multiple_atom || target == save_targets_atom)
224 return false; 227 return false;
225 228
229 if (target == timestamp_atom) {
230 XChangeProperty(
231 x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace,
232 reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1);
233 return true;
234 }
235
226 if (target == targets_atom) { 236 if (target == targets_atom) {
227 // We have been asked for TARGETS. Send an atom array back with the data 237 // We have been asked for TARGETS. Send an atom array back with the data
228 // types we support. 238 // types we support.
229 std::vector<XAtom> targets; 239 std::vector<XAtom> targets;
240 targets.push_back(timestamp_atom);
230 targets.push_back(targets_atom); 241 targets.push_back(targets_atom);
231 targets.push_back(save_targets_atom); 242 targets.push_back(save_targets_atom);
232 targets.push_back(multiple_atom); 243 targets.push_back(multiple_atom);
233 RetrieveTargets(&targets); 244 RetrieveTargets(&targets);
234 245
235 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, 246 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
236 PropModeReplace, 247 PropModeReplace,
237 reinterpret_cast<unsigned char*>(&targets.front()), 248 reinterpret_cast<unsigned char*>(&targets.front()),
238 targets.size()); 249 targets.size());
239 return true; 250 return true;
240 } else { 251 }
241 // Try to find the data type in map.
242 SelectionFormatMap::const_iterator it = format_map_.find(target);
243 if (it != format_map_.end()) {
244 if (it->second->size() > max_request_size_) {
245 // We must send the data back in several chunks due to a limitation in
246 // the size of X requests. Notify the selection requestor that the data
247 // will be sent incrementally by returning data of type "INCR".
248 long length = it->second->size();
249 XChangeProperty(x_display_,
250 requestor,
251 property,
252 atom_cache_.GetAtom(kIncr),
253 32,
254 PropModeReplace,
255 reinterpret_cast<unsigned char*>(&length),
256 1);
257 252
258 // Wait for the selection requestor to indicate that it has processed 253 // Try to find the data type in map.
259 // the selection result before sending the first chunk of data. The 254 SelectionFormatMap::const_iterator it = format_map_.find(target);
260 // selection requestor indicates this by deleting |property|. 255 if (it != format_map_.end()) {
261 base::TimeTicks timeout = 256 if (it->second->size() > max_request_size_) {
262 base::TimeTicks::Now() + 257 // We must send the data back in several chunks due to a limitation in
263 base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs); 258 // the size of X requests. Notify the selection requestor that the data
264 int foreign_window_manager_id = 259 // will be sent incrementally by returning data of type "INCR".
265 ui::XForeignWindowManager::GetInstance()->RequestEvents( 260 long length = it->second->size();
266 requestor, PropertyChangeMask); 261 XChangeProperty(x_display_,
267 incremental_transfers_.push_back( 262 requestor,
268 IncrementalTransfer(requestor, 263 property,
269 target, 264 atom_cache_.GetAtom(kIncr),
270 property, 265 32,
271 it->second, 266 PropModeReplace,
272 0, 267 reinterpret_cast<unsigned char*>(&length),
273 timeout, 268 1);
274 foreign_window_manager_id));
275 269
276 // Start a timer to abort the data transfer in case that the selection 270 // Wait for the selection requestor to indicate that it has processed
277 // requestor does not support the INCR property or gets destroyed during 271 // the selection result before sending the first chunk of data. The
278 // the data transfer. 272 // selection requestor indicates this by deleting |property|.
279 if (!incremental_transfer_abort_timer_.IsRunning()) { 273 base::TimeTicks timeout =
280 incremental_transfer_abort_timer_.Start( 274 base::TimeTicks::Now() +
281 FROM_HERE, 275 base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
282 base::TimeDelta::FromMilliseconds(kTimerPeriodMs), 276 int foreign_window_manager_id =
283 this, 277 ui::XForeignWindowManager::GetInstance()->RequestEvents(
284 &SelectionOwner::AbortStaleIncrementalTransfers); 278 requestor, PropertyChangeMask);
285 } 279 incremental_transfers_.push_back(
286 } else { 280 IncrementalTransfer(requestor,
287 XChangeProperty( 281 target,
288 x_display_, 282 property,
289 requestor, 283 it->second,
290 property, 284 0,
291 target, 285 timeout,
292 8, 286 foreign_window_manager_id));
293 PropModeReplace, 287
294 const_cast<unsigned char*>(it->second->front()), 288 // Start a timer to abort the data transfer in case that the selection
295 it->second->size()); 289 // requestor does not support the INCR property or gets destroyed during
290 // the data transfer.
291 if (!incremental_transfer_abort_timer_.IsRunning()) {
292 incremental_transfer_abort_timer_.Start(
293 FROM_HERE,
294 base::TimeDelta::FromMilliseconds(kTimerPeriodMs),
295 this,
296 &SelectionOwner::AbortStaleIncrementalTransfers);
296 } 297 }
297 return true; 298 } else {
299 XChangeProperty(
300 x_display_,
301 requestor,
302 property,
303 target,
304 8,
305 PropModeReplace,
306 const_cast<unsigned char*>(it->second->front()),
307 it->second->size());
298 } 308 }
299 // I would put error logging here, but GTK ignores TARGETS and spams us 309 return true;
300 // looking for its own internal types.
301 } 310 }
311
312 // I would put error logging here, but GTK ignores TARGETS and spams us
313 // looking for its own internal types.
302 return false; 314 return false;
303 } 315 }
304 316
305 void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) { 317 void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
306 size_t remaining = transfer->data->size() - transfer->offset; 318 size_t remaining = transfer->data->size() - transfer->offset;
307 size_t chunk_length = std::min(remaining, max_request_size_); 319 size_t chunk_length = std::min(remaining, max_request_size_);
308 XChangeProperty( 320 XChangeProperty(
309 x_display_, 321 x_display_,
310 transfer->window, 322 transfer->window,
311 transfer->property, 323 transfer->property,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 foreign_window_manager_id(foreign_window_manager_id) { 388 foreign_window_manager_id(foreign_window_manager_id) {
377 } 389 }
378 390
379 SelectionOwner::IncrementalTransfer::IncrementalTransfer( 391 SelectionOwner::IncrementalTransfer::IncrementalTransfer(
380 const IncrementalTransfer& other) = default; 392 const IncrementalTransfer& other) = default;
381 393
382 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { 394 SelectionOwner::IncrementalTransfer::~IncrementalTransfer() {
383 } 395 }
384 396
385 } // namespace ui 397 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/x/selection_owner.h ('k') | ui/events/platform/x11/x11_event_source.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698