| 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 |