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

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

Issue 397223002: Enable copying long text to Chrome and pasting long text from Chrome (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « ui/base/x/selection_requestor.h ('k') | ui/base/x/x11_foreign_window_manager.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_requestor.h" 5 #include "ui/base/x/selection_requestor.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <X11/Xlib.h> 8 #include <X11/Xlib.h>
9 9
10 #include "base/run_loop.h" 10 #include "base/run_loop.h"
11 #include "ui/base/x/selection_utils.h" 11 #include "ui/base/x/selection_utils.h"
12 #include "ui/base/x/x11_util.h" 12 #include "ui/base/x/x11_util.h"
13 #include "ui/events/platform/platform_event_dispatcher.h" 13 #include "ui/events/platform/platform_event_dispatcher.h"
14 #include "ui/events/platform/platform_event_source.h" 14 #include "ui/events/platform/platform_event_source.h"
15 #include "ui/gfx/x/x11_types.h" 15 #include "ui/gfx/x/x11_types.h"
16 16
17 namespace ui { 17 namespace ui {
18 18
19 namespace { 19 namespace {
20 20
21 const char kChromeSelection[] = "CHROME_SELECTION"; 21 const char kChromeSelection[] = "CHROME_SELECTION";
22 const char kIncr[] = "INCR";
22 23
23 const char* kAtomsToCache[] = { 24 const char* kAtomsToCache[] = {
24 kChromeSelection, 25 kChromeSelection,
26 kIncr,
25 NULL 27 NULL
26 }; 28 };
27 29
28 // The amount of time to wait for a request to complete. 30 // The period of |abort_timer_|. Arbitrary but must be <= than
29 const int kRequestTimeoutMs = 300; 31 // kRequestTimeoutMs.
32 const int kTimerPeriodMs = 100;
33
34 // The amount of time to wait for a request to complete before aborting it.
35 const int kRequestTimeoutMs = 10000;
36
37 COMPILE_ASSERT(kTimerPeriodMs <= kRequestTimeoutMs,
38 timer_period_must_be_less_or_equal_to_request_timeout);
39
40 // Combines |data| into a single RefCountedMemory object.
41 scoped_refptr<base::RefCountedMemory> CombineRefCountedMemory(
42 const std::vector<scoped_refptr<base::RefCountedMemory> >& data) {
43 if (data.size() == 1u)
44 return data[0];
45
46 size_t length = 0;
47 for (size_t i = 0; i < data.size(); ++i)
48 length += data[i]->size();
49 std::vector<unsigned char> combined_data;
50 combined_data.reserve(length);
51
52 for (size_t i = 0; i < data.size(); ++i) {
53 combined_data.insert(combined_data.end(),
54 data[i]->front(),
55 data[i]->front() + data[i]->size());
56 }
57 return scoped_refptr<base::RefCountedMemory>(
58 base::RefCountedBytes::TakeVector(&combined_data));
59 }
30 60
31 } // namespace 61 } // namespace
32 62
33 SelectionRequestor::SelectionRequestor(XDisplay* x_display, 63 SelectionRequestor::SelectionRequestor(XDisplay* x_display,
34 XID x_window, 64 XID x_window,
35 PlatformEventDispatcher* dispatcher) 65 PlatformEventDispatcher* dispatcher)
36 : x_display_(x_display), 66 : x_display_(x_display),
37 x_window_(x_window), 67 x_window_(x_window),
38 x_property_(None), 68 x_property_(None),
39 dispatcher_(dispatcher), 69 dispatcher_(dispatcher),
40 current_request_index_(0u), 70 current_request_index_(0u),
41 atom_cache_(x_display_, kAtomsToCache) { 71 atom_cache_(x_display_, kAtomsToCache) {
42 x_property_ = atom_cache_.GetAtom(kChromeSelection); 72 x_property_ = atom_cache_.GetAtom(kChromeSelection);
43 } 73 }
44 74
45 SelectionRequestor::~SelectionRequestor() {} 75 SelectionRequestor::~SelectionRequestor() {}
46 76
47 bool SelectionRequestor::PerformBlockingConvertSelection( 77 bool SelectionRequestor::PerformBlockingConvertSelection(
48 XAtom selection, 78 XAtom selection,
49 XAtom target, 79 XAtom target,
50 scoped_refptr<base::RefCountedMemory>* out_data, 80 scoped_refptr<base::RefCountedMemory>* out_data,
51 size_t* out_data_items, 81 size_t* out_data_items,
52 XAtom* out_type) { 82 XAtom* out_type) {
53 base::TimeTicks timeout = 83 base::TimeTicks timeout =
54 base::TimeTicks::Now() + 84 base::TimeTicks::Now() +
55 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); 85 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
56 Request request(selection, target, timeout); 86 Request request(selection, target, timeout);
57 requests_.push_back(&request); 87 requests_.push_back(&request);
58 if (requests_.size() == 1u) 88 if (current_request_index_ == (requests_.size() - 1))
59 ConvertSelectionForCurrentRequest(); 89 ConvertSelectionForCurrentRequest();
60 BlockTillSelectionNotifyForRequest(&request); 90 BlockTillSelectionNotifyForRequest(&request);
61 91
62 std::vector<Request*>::iterator request_it = std::find( 92 std::vector<Request*>::iterator request_it = std::find(
63 requests_.begin(), requests_.end(), &request); 93 requests_.begin(), requests_.end(), &request);
64 CHECK(request_it != requests_.end()); 94 CHECK(request_it != requests_.end());
65 if (static_cast<int>(current_request_index_) > 95 if (static_cast<int>(current_request_index_) >
66 request_it - requests_.begin()) { 96 request_it - requests_.begin()) {
67 --current_request_index_; 97 --current_request_index_;
68 } 98 }
69 requests_.erase(request_it); 99 requests_.erase(request_it);
70 100
71 if (requests_.empty()) 101 if (requests_.empty())
72 abort_timer_.Stop(); 102 abort_timer_.Stop();
73 103
74 if (request.success) { 104 if (request.success) {
75 if (out_data) 105 if (out_data)
76 *out_data = request.out_data; 106 *out_data = CombineRefCountedMemory(request.out_data);
77 if (out_data_items) 107 if (out_data_items)
78 *out_data_items = request.out_data_items; 108 *out_data_items = request.out_data_items;
79 if (out_type) 109 if (out_type)
80 *out_type = request.out_type; 110 *out_type = request.out_type;
81 } 111 }
82 return request.success; 112 return request.success;
83 } 113 }
84 114
85 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( 115 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
86 XAtom selection, 116 XAtom selection,
(...skipping 29 matching lines...) Expand all
116 if (!request || 146 if (!request ||
117 request->completed || 147 request->completed ||
118 request->selection != event.xselection.selection || 148 request->selection != event.xselection.selection ||
119 request->target != event.xselection.target) { 149 request->target != event.xselection.target) {
120 // ICCCM requires us to delete the property passed into SelectionNotify. 150 // ICCCM requires us to delete the property passed into SelectionNotify.
121 if (event_property != None) 151 if (event_property != None)
122 XDeleteProperty(x_display_, x_window_, event_property); 152 XDeleteProperty(x_display_, x_window_, event_property);
123 return; 153 return;
124 } 154 }
125 155
126 request->success = false; 156 bool success = false;
127 if (event_property == x_property_) { 157 if (event_property == x_property_) {
128 request->success = ui::GetRawBytesOfProperty(x_window_, 158 scoped_refptr<base::RefCountedMemory> out_data;
129 x_property_, 159 success = ui::GetRawBytesOfProperty(x_window_,
130 &request->out_data, 160 x_property_,
131 &request->out_data_items, 161 &out_data,
132 &request->out_type); 162 &request->out_data_items,
163 &request->out_type);
164 if (success) {
165 request->out_data.clear();
166 request->out_data.push_back(out_data);
167 }
133 } 168 }
134 if (event_property != None) 169 if (event_property != None)
135 XDeleteProperty(x_display_, x_window_, event_property); 170 XDeleteProperty(x_display_, x_window_, event_property);
136 171
137 CompleteRequest(current_request_index_); 172 if (request->out_type == atom_cache_.GetAtom(kIncr)) {
173 request->data_sent_incrementally = true;
174 request->out_data.clear();
175 request->out_data_items = 0u;
176 request->out_type = None;
177 request->timeout = base::TimeTicks::Now() +
178 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
179 } else {
180 CompleteRequest(current_request_index_, success);
181 }
182 }
183
184 bool SelectionRequestor::CanDispatchPropertyEvent(const XEvent& event) {
185 return event.xproperty.window == x_window_ &&
186 event.xproperty.atom == x_property_ &&
187 event.xproperty.state == PropertyNewValue;
188 }
189
190 void SelectionRequestor::OnPropertyEvent(const XEvent& event) {
191 Request* request = GetCurrentRequest();
192 if (!request || !request->data_sent_incrementally)
193 return;
194
195 scoped_refptr<base::RefCountedMemory> out_data;
196 size_t out_data_items = 0u;
197 Atom out_type = None;
198 bool success = ui::GetRawBytesOfProperty(x_window_,
199 x_property_,
200 &out_data,
201 &out_data_items,
202 &out_type);
203 if (!success) {
204 CompleteRequest(current_request_index_, false);
205 return;
206 }
207
208 if (request->out_type != None && request->out_type != out_type) {
209 CompleteRequest(current_request_index_, false);
210 return;
211 }
212
213 request->out_data.push_back(out_data);
214 request->out_data_items += out_data_items;
215 request->out_type = out_type;
216
217 // Delete the property to tell the selection owner to send the next chunk.
218 XDeleteProperty(x_display_, x_window_, x_property_);
219
220 request->timeout = base::TimeTicks::Now() +
221 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
222
223 if (out_data->size() == 0u)
224 CompleteRequest(current_request_index_, true);
138 } 225 }
139 226
140 void SelectionRequestor::AbortStaleRequests() { 227 void SelectionRequestor::AbortStaleRequests() {
141 base::TimeTicks now = base::TimeTicks::Now(); 228 base::TimeTicks now = base::TimeTicks::Now();
142 for (size_t i = current_request_index_; 229 for (size_t i = current_request_index_; i < requests_.size(); ++i) {
143 i < requests_.size() && requests_[i]->timeout <= now; 230 if (requests_[i]->timeout <= now)
144 ++i) { 231 CompleteRequest(i, false);
145 CompleteRequest(i);
146 } 232 }
147 } 233 }
148 234
149 void SelectionRequestor::CompleteRequest(size_t index) { 235 void SelectionRequestor::CompleteRequest(size_t index, bool success) {
150 if (index >= requests_.size()) 236 if (index >= requests_.size())
151 return; 237 return;
152 238
153 Request* request = requests_[index]; 239 Request* request = requests_[index];
154 if (request->completed) 240 if (request->completed)
155 return; 241 return;
242 request->success = success;
156 request->completed = true; 243 request->completed = true;
157 244
158 if (index == current_request_index_) { 245 if (index == current_request_index_) {
159 ++current_request_index_; 246 while (GetCurrentRequest() && GetCurrentRequest()->completed)
247 ++current_request_index_;
160 ConvertSelectionForCurrentRequest(); 248 ConvertSelectionForCurrentRequest();
161 } 249 }
162 250
163 if (!request->quit_closure.is_null()) 251 if (!request->quit_closure.is_null())
164 request->quit_closure.Run(); 252 request->quit_closure.Run();
165 } 253 }
166 254
167 void SelectionRequestor::ConvertSelectionForCurrentRequest() { 255 void SelectionRequestor::ConvertSelectionForCurrentRequest() {
168 Request* request = GetCurrentRequest(); 256 Request* request = GetCurrentRequest();
169 if (request) { 257 if (request) {
170 XConvertSelection(x_display_, 258 XConvertSelection(x_display_,
171 request->selection, 259 request->selection,
172 request->target, 260 request->target,
173 x_property_, 261 x_property_,
174 x_window_, 262 x_window_,
175 CurrentTime); 263 CurrentTime);
176 } 264 }
177 } 265 }
178 266
179 void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) { 267 void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
180 if (PlatformEventSource::GetInstance()) { 268 if (PlatformEventSource::GetInstance()) {
181 if (!abort_timer_.IsRunning()) { 269 if (!abort_timer_.IsRunning()) {
182 abort_timer_.Start(FROM_HERE, 270 abort_timer_.Start(FROM_HERE,
183 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs), 271 base::TimeDelta::FromMilliseconds(kTimerPeriodMs),
184 this, 272 this,
185 &SelectionRequestor::AbortStaleRequests); 273 &SelectionRequestor::AbortStaleRequests);
186 } 274 }
187 275
188 base::MessageLoop::ScopedNestableTaskAllower allow_nested( 276 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
189 base::MessageLoopForUI::current()); 277 base::MessageLoopForUI::current());
190 base::RunLoop run_loop; 278 base::RunLoop run_loop;
191 request->quit_closure = run_loop.QuitClosure(); 279 request->quit_closure = run_loop.QuitClosure();
192 run_loop.Run(); 280 run_loop.Run();
193 281
(...skipping 18 matching lines...) Expand all
212 SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() { 300 SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
213 return current_request_index_ == requests_.size() ? 301 return current_request_index_ == requests_.size() ?
214 NULL : requests_[current_request_index_]; 302 NULL : requests_[current_request_index_];
215 } 303 }
216 304
217 SelectionRequestor::Request::Request(XAtom selection, 305 SelectionRequestor::Request::Request(XAtom selection,
218 XAtom target, 306 XAtom target,
219 base::TimeTicks timeout) 307 base::TimeTicks timeout)
220 : selection(selection), 308 : selection(selection),
221 target(target), 309 target(target),
310 data_sent_incrementally(false),
222 out_data_items(0u), 311 out_data_items(0u),
223 out_type(None), 312 out_type(None),
224 success(false), 313 success(false),
225 timeout(timeout), 314 timeout(timeout),
226 completed(false) { 315 completed(false) {
227 } 316 }
228 317
229 SelectionRequestor::Request::~Request() { 318 SelectionRequestor::Request::~Request() {
230 } 319 }
231 320
232 } // namespace ui 321 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/x/selection_requestor.h ('k') | ui/base/x/x11_foreign_window_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698