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

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

Issue 391593002: Process SelectionRequestor::PerformBlockingConvertSelection() requests one at a time (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
« no previous file with comments | « ui/base/x/selection_requestor.h ('k') | no next file » | 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 "base/run_loop.h" 7 #include "base/run_loop.h"
8 #include "ui/base/x/selection_utils.h" 8 #include "ui/base/x/selection_utils.h"
9 #include "ui/base/x/x11_util.h" 9 #include "ui/base/x/x11_util.h"
10 #include "ui/events/platform/platform_event_dispatcher.h" 10 #include "ui/events/platform/platform_event_dispatcher.h"
11 #include "ui/events/platform/platform_event_source.h" 11 #include "ui/events/platform/platform_event_source.h"
12 #include "ui/gfx/x/x11_types.h" 12 #include "ui/gfx/x/x11_types.h"
13 13
14 namespace ui { 14 namespace ui {
15 15
16 namespace { 16 namespace {
17 17
18 const char kChromeSelection[] = "CHROME_SELECTION"; 18 // Properties to be used in XConvertSelection() requests. The number of
19 // properties is arbitrary.
20 const char* kChromeSelectionProperties[] = {
21 "CHROME_SELECTION0",
22 "CHROME_SELECTION1",
23 "CHROME_SELECTION2",
24 "CHROME_SELECTION3",
25 "CHROME_SELECTION4"
26 };
19 27
20 const char* kAtomsToCache[] = { 28 const char* kAtomsToCache[] = {
21 kChromeSelection, 29 kChromeSelectionProperties[0],
30 kChromeSelectionProperties[1],
31 kChromeSelectionProperties[2],
32 kChromeSelectionProperties[3],
33 kChromeSelectionProperties[4],
22 NULL 34 NULL
23 }; 35 };
24 36
25 } // namespace 37 } // namespace
26 38
27 SelectionRequestor::SelectionRequestor(Display* x_display, 39 SelectionRequestor::SelectionRequestor(Display* x_display,
28 Window x_window, 40 Window x_window,
29 Atom selection_name,
30 PlatformEventDispatcher* dispatcher) 41 PlatformEventDispatcher* dispatcher)
31 : x_display_(x_display), 42 : x_display_(x_display),
32 x_window_(x_window), 43 x_window_(x_window),
33 selection_name_(selection_name),
34 dispatcher_(dispatcher), 44 dispatcher_(dispatcher),
45 property_pool_(kChromeSelectionProperties,
46 kChromeSelectionProperties
47 + arraysize(kChromeSelectionProperties)),
35 atom_cache_(x_display_, kAtomsToCache) { 48 atom_cache_(x_display_, kAtomsToCache) {
36 } 49 }
37 50
38 SelectionRequestor::~SelectionRequestor() {} 51 SelectionRequestor::~SelectionRequestor() {}
39 52
40 bool SelectionRequestor::PerformBlockingConvertSelection( 53 bool SelectionRequestor::PerformBlockingConvertSelection(
54 Atom selection,
41 Atom target, 55 Atom target,
42 scoped_refptr<base::RefCountedMemory>* out_data, 56 scoped_refptr<base::RefCountedMemory>* out_data,
43 size_t* out_data_items, 57 size_t* out_data_items,
44 Atom* out_type) { 58 Atom* out_type) {
45 // The name of the property that we are either: 59 // Find a property for XConvertSelection() to use. The selection owner will
46 // - Passing as a parameter with the XConvertSelection() request. 60 // set |property| on |xwindow_| with the data for the requested target. If
47 // OR 61 // there is no available property, make the request fail.
48 // - Asking the selection owner to set on |x_window_|. 62 if (property_pool_.empty())
49 Atom property = atom_cache_.GetAtom(kChromeSelection); 63 return false;
50 64
51 XConvertSelection(x_display_, 65 const char* property_name = property_pool_.back();
52 selection_name_, 66 property_pool_.pop_back();
Daniel Erat 2014/07/15 01:04:09 with the disclaimer that i don't know much about s
pkotwicz 2014/07/15 02:07:24 The problem is that there are callers of clipboard
Daniel Erat 2014/07/15 03:32:01 oh. is the nested message loop in BlockTillSelecti
53 target, 67 bool success = PerformBlockingConvertSelectionImpl(selection, target,
54 property, 68 property_name, out_data, out_data_items, out_type);
55 x_window_, 69 property_pool_.push_back(property_name);
56 CurrentTime);
57
58 // Now that we've thrown our message off to the X11 server, we block waiting
59 // for a response.
60 PendingRequest pending_request(target);
61 BlockTillSelectionNotifyForRequest(&pending_request);
62
63 bool success = false;
64 if (pending_request.returned_property == property) {
65 success = ui::GetRawBytesOfProperty(x_window_,
66 pending_request.returned_property,
67 out_data, out_data_items, out_type);
68 }
69 if (pending_request.returned_property != None)
70 XDeleteProperty(x_display_, x_window_, pending_request.returned_property);
71 return success; 70 return success;
72 } 71 }
73 72
74 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( 73 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
74 Atom selection,
75 Atom target, 75 Atom target,
76 const std::vector< ::Atom>& parameter) { 76 const std::vector< ::Atom>& parameter) {
77 SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); 77 if (property_pool_.empty())
78 PerformBlockingConvertSelection(target, NULL, NULL, NULL); 78 return;
79 const char* property_name = property_pool_.back();
80 property_pool_.pop_back();
81 SetAtomArrayProperty(x_window_, property_name, "ATOM", parameter);
82 PerformBlockingConvertSelectionImpl(selection, target, property_name, NULL,
83 NULL, NULL);
84 property_pool_.push_back(property_name);
79 } 85 }
80 86
81 SelectionData SelectionRequestor::RequestAndWaitForTypes( 87 SelectionData SelectionRequestor::RequestAndWaitForTypes(
88 Atom selection,
82 const std::vector< ::Atom>& types) { 89 const std::vector< ::Atom>& types) {
83 for (std::vector< ::Atom>::const_iterator it = types.begin(); 90 for (std::vector< ::Atom>::const_iterator it = types.begin();
84 it != types.end(); ++it) { 91 it != types.end(); ++it) {
85 scoped_refptr<base::RefCountedMemory> data; 92 scoped_refptr<base::RefCountedMemory> data;
86 ::Atom type = None; 93 ::Atom type = None;
87 if (PerformBlockingConvertSelection(*it, 94 if (PerformBlockingConvertSelection(selection,
95 *it,
88 &data, 96 &data,
89 NULL, 97 NULL,
90 &type) && 98 &type) &&
91 type == *it) { 99 type == *it) {
92 return SelectionData(type, data); 100 return SelectionData(type, data);
93 } 101 }
94 } 102 }
95 103
96 return SelectionData(); 104 return SelectionData();
97 } 105 }
98 106
99 void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) { 107 void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) {
100 // Find the PendingRequest for the corresponding XConvertSelection call. If 108 // Find the PendingRequest for the corresponding XConvertSelection call. If
101 // there are multiple pending requests on the same target, satisfy them in 109 // there are multiple pending requests on the same target, satisfy them in
102 // FIFO order. 110 // FIFO order.
103 PendingRequest* request_notified = NULL; 111 PendingRequest* request_notified = NULL;
104 if (selection_name_ == event.selection) { 112 for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin();
105 for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin(); 113 iter != pending_requests_.end(); ++iter) {
106 iter != pending_requests_.end(); ++iter) { 114 PendingRequest* request = *iter;
107 PendingRequest* request = *iter; 115 if (!request->returned &&
108 if (request->returned) 116 request->selection == event.selection &&
109 continue; 117 request->target == event.target) {
110 if (request->target != event.target)
111 continue;
112 request_notified = request; 118 request_notified = request;
113 break; 119 break;
114 } 120 }
115 } 121 }
116 122
117 // This event doesn't correspond to any XConvertSelection calls that we 123 // This event doesn't correspond to any XConvertSelection calls that we
118 // issued in PerformBlockingConvertSelection. This shouldn't happen, but any 124 // issued in PerformBlockingConvertSelection. This shouldn't happen, but any
119 // client can send any message, so it can happen. 125 // client can send any message, so it can happen.
120 if (!request_notified) { 126 if (!request_notified) {
121 // ICCCM requires us to delete the property passed into SelectionNotify. If 127 // ICCCM requires us to delete the property passed into SelectionNotify. If
122 // |request_notified| is true, the property will be deleted when the run 128 // |request_notified| is true, the property will be deleted when the run
123 // loop has quit. 129 // loop has quit.
124 if (event.property != None) 130 if (event.property != None)
125 XDeleteProperty(x_display_, x_window_, event.property); 131 XDeleteProperty(x_display_, x_window_, event.property);
126 return; 132 return;
127 } 133 }
128 134
129 request_notified->returned_property = event.property; 135 request_notified->returned_property = event.property;
130 request_notified->returned = true; 136 request_notified->returned = true;
131 137
132 if (!request_notified->quit_closure.is_null()) 138 if (!request_notified->quit_closure.is_null())
133 request_notified->quit_closure.Run(); 139 request_notified->quit_closure.Run();
134 } 140 }
135 141
142 bool SelectionRequestor::PerformBlockingConvertSelectionImpl(
143 Atom selection,
144 Atom target,
145 const char* property_name,
146 scoped_refptr<base::RefCountedMemory>* out_data,
147 size_t* out_data_items,
148 Atom* out_type) {
149 Atom property = atom_cache_.GetAtom(property_name);
150 XConvertSelection(x_display_,
151 selection,
152 target,
153 property,
154 x_window_,
155 CurrentTime);
156
157 // Now that we've thrown our message off to the X11 server, we block waiting
158 // for a response.
159 PendingRequest pending_request(selection, target);
160 BlockTillSelectionNotifyForRequest(&pending_request);
161
162 bool success = false;
163 if (pending_request.returned_property == property) {
164 success = ui::GetRawBytesOfProperty(x_window_,
165 pending_request.returned_property,
166 out_data, out_data_items, out_type);
167 }
168 if (pending_request.returned_property != None)
169 XDeleteProperty(x_display_, x_window_, pending_request.returned_property);
170 return success;
171 }
172
136 void SelectionRequestor::BlockTillSelectionNotifyForRequest( 173 void SelectionRequestor::BlockTillSelectionNotifyForRequest(
137 PendingRequest* request) { 174 PendingRequest* request) {
138 pending_requests_.push_back(request); 175 pending_requests_.push_back(request);
139 176
140 const int kMaxWaitTimeForClipboardResponse = 300; 177 const int kMaxWaitTimeForClipboardResponse = 300;
141 if (PlatformEventSource::GetInstance()) { 178 if (PlatformEventSource::GetInstance()) {
142 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 179 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
143 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop); 180 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
144 base::RunLoop run_loop; 181 base::RunLoop run_loop;
145 182
(...skipping 18 matching lines...) Expand all
164 if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse) 201 if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse)
165 break; 202 break;
166 } 203 }
167 } 204 }
168 205
169 DCHECK(!pending_requests_.empty()); 206 DCHECK(!pending_requests_.empty());
170 DCHECK_EQ(request, pending_requests_.back()); 207 DCHECK_EQ(request, pending_requests_.back());
171 pending_requests_.pop_back(); 208 pending_requests_.pop_back();
172 } 209 }
173 210
174 SelectionRequestor::PendingRequest::PendingRequest(Atom target) 211 SelectionRequestor::PendingRequest::PendingRequest(Atom requested_selection,
175 : target(target), 212 Atom requested_target)
213 : selection(requested_selection),
214 target(requested_target),
176 returned_property(None), 215 returned_property(None),
177 returned(false) { 216 returned(false) {
178 } 217 }
179 218
180 SelectionRequestor::PendingRequest::~PendingRequest() { 219 SelectionRequestor::PendingRequest::~PendingRequest() {
181 } 220 }
182 221
183 } // namespace ui 222 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/x/selection_requestor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698