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

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, 5 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
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.
Daniel Erat 2014/07/25 19:38:44 add a compile-time assert of this constraint?
pkotwicz 2014/07/26 20:09:53 Done.
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 // Combines |data| into a single RefCountedMemory object.
38 scoped_refptr<base::RefCountedMemory> CombineRefCountedMemory(
39 const std::vector<scoped_refptr<base::RefCountedMemory> >& data) {
40 if (data.size() == 1u)
41 return data[0];
42
43 size_t length = 0;
44 for (size_t i = 0; i < data.size(); ++i)
45 length += data[i]->size();
46 std::vector<unsigned char> combined_data;
47 combined_data.reserve(length);
48
49 for (size_t i = 0; i < data.size(); ++i) {
50 combined_data.insert(combined_data.end(),
51 data[i]->front(),
52 data[i]->front() + data[i]->size());
53 }
54 return scoped_refptr<base::RefCountedMemory>(
55 base::RefCountedBytes::TakeVector(&combined_data));
56 }
30 57
31 } // namespace 58 } // namespace
32 59
33 SelectionRequestor::SelectionRequestor(XDisplay* x_display, 60 SelectionRequestor::SelectionRequestor(XDisplay* x_display,
34 XID x_window, 61 XID x_window,
35 PlatformEventDispatcher* dispatcher) 62 PlatformEventDispatcher* dispatcher)
36 : x_display_(x_display), 63 : x_display_(x_display),
37 x_window_(x_window), 64 x_window_(x_window),
38 x_property_(None), 65 x_property_(None),
39 dispatcher_(dispatcher), 66 dispatcher_(dispatcher),
(...skipping 25 matching lines...) Expand all
65 if (static_cast<int>(current_request_index_) > 92 if (static_cast<int>(current_request_index_) >
66 request_it - requests_.begin()) { 93 request_it - requests_.begin()) {
67 --current_request_index_; 94 --current_request_index_;
68 } 95 }
69 requests_.erase(request_it); 96 requests_.erase(request_it);
70 97
71 if (requests_.empty()) 98 if (requests_.empty())
72 abort_timer_.Stop(); 99 abort_timer_.Stop();
73 100
74 if (out_data) 101 if (out_data)
75 *out_data = request.out_data; 102 *out_data = CombineRefCountedMemory(request.out_data);
76 if (out_data_items) 103 if (out_data_items)
77 *out_data_items = request.out_data_items; 104 *out_data_items = request.out_data_items;
78 if (out_type) 105 if (out_type)
79 *out_type = request.out_type; 106 *out_type = request.out_type;
80 return request.success; 107 return request.success;
81 } 108 }
82 109
83 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( 110 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
84 XAtom selection, 111 XAtom selection,
85 XAtom target, 112 XAtom target,
(...skipping 28 matching lines...) Expand all
114 if (!request || 141 if (!request ||
115 request->completed || 142 request->completed ||
116 request->selection != event.xselection.selection || 143 request->selection != event.xselection.selection ||
117 request->target != event.xselection.target) { 144 request->target != event.xselection.target) {
118 // ICCCM requires us to delete the property passed into SelectionNotify. 145 // ICCCM requires us to delete the property passed into SelectionNotify.
119 if (event_property != None) 146 if (event_property != None)
120 XDeleteProperty(x_display_, x_window_, event_property); 147 XDeleteProperty(x_display_, x_window_, event_property);
121 return; 148 return;
122 } 149 }
123 150
124 request->success = false; 151 bool success = false;
125 if (event_property == x_property_) { 152 if (event_property == x_property_) {
126 request->success = ui::GetRawBytesOfProperty(x_window_, 153 scoped_refptr<base::RefCountedMemory> out_data;
127 x_property_, 154 success = ui::GetRawBytesOfProperty(x_window_,
128 &request->out_data, 155 x_property_,
129 &request->out_data_items, 156 &out_data,
130 &request->out_type); 157 &request->out_data_items,
158 &request->out_type);
159 if (success)
160 request->out_data.push_back(out_data);
131 } 161 }
132 if (event_property != None) 162 if (event_property != None)
133 XDeleteProperty(x_display_, x_window_, event_property); 163 XDeleteProperty(x_display_, x_window_, event_property);
134 164
135 CompleteRequest(current_request_index_); 165 if (request->out_type == atom_cache_.GetAtom(kIncr)) {
166 request->data_sent_incrementally = true;
167 request->out_type = None;
168 request->timeout = base::TimeTicks::Now() +
169 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
170 } else {
171 CompleteRequest(current_request_index_, success);
172 }
173 }
174
175 bool SelectionRequestor::CanDispatchPropertyEvent(const XEvent& event) {
176 return event.xproperty.window == x_window_ &&
177 event.xproperty.atom == x_property_ &&
178 event.xproperty.state == PropertyNewValue;
179 }
180
181 void SelectionRequestor::OnPropertyEvent(const XEvent& event) {
182 Request* request = GetCurrentRequest();
183 if (!request)
184 return;
185
186 scoped_refptr<base::RefCountedMemory> out_data;
187 size_t out_data_items = 0u;
188 Atom out_type = None;
189 bool success = ui::GetRawBytesOfProperty(x_window_,
190 x_property_,
191 &out_data,
192 &out_data_items,
193 &out_type);
194 if (!success) {
195 CompleteRequest(current_request_index_, false);
196 return;
197 }
198
199 if (request->out_type != None && request->out_type != out_type) {
200 CompleteRequest(current_request_index_, false);
201 return;
202 }
203
204 request->out_data.push_back(out_data);
205 request->out_data_items += out_data_items;
206 request->out_type = out_type;
207
208 // Delete the property to tell the selection owner to send the next chunk.
209 XDeleteProperty(x_display_, x_window_, x_property_);
210
211 request->timeout = base::TimeTicks::Now() +
212 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
213
214 if (out_data->size() == 0u)
215 CompleteRequest(current_request_index_, true);
136 } 216 }
137 217
138 void SelectionRequestor::AbortStaleRequests() { 218 void SelectionRequestor::AbortStaleRequests() {
139 base::TimeTicks now = base::TimeTicks::Now(); 219 base::TimeTicks now = base::TimeTicks::Now();
140 for (size_t i = 0; i < requests_.size(); ++i) { 220 for (size_t i = 0; i < requests_.size(); ++i) {
141 if (requests_[i]->timeout <= now) 221 if (requests_[i]->timeout <= now)
142 CompleteRequest(i); 222 CompleteRequest(i, false);
143 } 223 }
144 } 224 }
145 225
146 void SelectionRequestor::CompleteRequest(size_t index) { 226 void SelectionRequestor::CompleteRequest(size_t index, bool success) {
147 if (index >= requests_.size()) 227 if (index >= requests_.size())
148 return; 228 return;
149 229
150 Request* request = requests_[index]; 230 Request* request = requests_[index];
151 if (request->completed) 231 if (request->completed)
152 return; 232 return;
233 request->success = success;
153 request->completed = true; 234 request->completed = true;
154 235
155 if (index == current_request_index_) { 236 if (index == current_request_index_) {
156 ++current_request_index_; 237 ++current_request_index_;
157 ConvertSelectionForCurrentRequest(); 238 ConvertSelectionForCurrentRequest();
158 } 239 }
159 240
160 if (!request->quit_closure.is_null()) 241 if (!request->quit_closure.is_null())
161 request->quit_closure.Run(); 242 request->quit_closure.Run();
162 } 243 }
163 244
164 void SelectionRequestor::ConvertSelectionForCurrentRequest() { 245 void SelectionRequestor::ConvertSelectionForCurrentRequest() {
165 Request* request = GetCurrentRequest(); 246 Request* request = GetCurrentRequest();
166 if (request) { 247 if (request) {
167 XConvertSelection(x_display_, 248 XConvertSelection(x_display_,
168 request->selection, 249 request->selection,
169 request->target, 250 request->target,
170 x_property_, 251 x_property_,
171 x_window_, 252 x_window_,
172 CurrentTime); 253 CurrentTime);
173 } 254 }
174 } 255 }
175 256
176 void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) { 257 void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
177 if (PlatformEventSource::GetInstance()) { 258 if (PlatformEventSource::GetInstance()) {
178 if (!abort_timer_.IsRunning()) { 259 if (!abort_timer_.IsRunning()) {
179 abort_timer_.Start(FROM_HERE, 260 abort_timer_.Start(FROM_HERE,
180 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs), 261 base::TimeDelta::FromMilliseconds(kTimerPeriodMs),
181 this, 262 this,
182 &SelectionRequestor::AbortStaleRequests); 263 &SelectionRequestor::AbortStaleRequests);
183 } 264 }
184 265
185 base::MessageLoop::ScopedNestableTaskAllower allow_nested( 266 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
186 base::MessageLoopForUI::current()); 267 base::MessageLoopForUI::current());
187 base::RunLoop run_loop; 268 base::RunLoop run_loop;
188 request->quit_closure = run_loop.QuitClosure(); 269 request->quit_closure = run_loop.QuitClosure();
189 run_loop.Run(); 270 run_loop.Run();
190 271
(...skipping 18 matching lines...) Expand all
209 SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() { 290 SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
210 return current_request_index_ == requests_.size() ? 291 return current_request_index_ == requests_.size() ?
211 NULL : requests_[current_request_index_]; 292 NULL : requests_[current_request_index_];
212 } 293 }
213 294
214 SelectionRequestor::Request::Request(XAtom selection, 295 SelectionRequestor::Request::Request(XAtom selection,
215 XAtom target, 296 XAtom target,
216 base::TimeTicks timeout) 297 base::TimeTicks timeout)
217 : selection(selection), 298 : selection(selection),
218 target(target), 299 target(target),
300 data_sent_incrementally(false),
219 out_data_items(0u), 301 out_data_items(0u),
220 out_type(None), 302 out_type(None),
221 success(false), 303 success(false),
222 timeout(timeout), 304 timeout(timeout),
223 completed(false) { 305 completed(false) {
224 } 306 }
225 307
226 SelectionRequestor::Request::~Request() { 308 SelectionRequestor::Request::~Request() {
227 } 309 }
228 310
229 } // namespace ui 311 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698