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_requestor.h" | 5 #include "ui/base/x/selection_requestor.h" |
6 | 6 |
| 7 #include <X11/Xlib.h> |
| 8 |
7 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
8 #include "ui/base/x/selection_utils.h" | 10 #include "ui/base/x/selection_utils.h" |
9 #include "ui/base/x/x11_util.h" | 11 #include "ui/base/x/x11_util.h" |
10 #include "ui/events/platform/platform_event_dispatcher.h" | 12 #include "ui/events/platform/platform_event_dispatcher.h" |
11 #include "ui/events/platform/platform_event_source.h" | 13 #include "ui/events/platform/platform_event_source.h" |
12 #include "ui/gfx/x/x11_types.h" | 14 #include "ui/gfx/x/x11_types.h" |
13 | 15 |
14 namespace ui { | 16 namespace ui { |
15 | 17 |
16 namespace { | 18 namespace { |
17 | 19 |
18 const char kChromeSelection[] = "CHROME_SELECTION"; | 20 const char kChromeSelection[] = "CHROME_SELECTION"; |
19 | 21 |
20 const char* kAtomsToCache[] = { | 22 const char* kAtomsToCache[] = { |
21 kChromeSelection, | 23 kChromeSelection, |
22 NULL | 24 NULL |
23 }; | 25 }; |
24 | 26 |
25 } // namespace | 27 } // namespace |
26 | 28 |
27 SelectionRequestor::SelectionRequestor(Display* x_display, | 29 SelectionRequestor::SelectionRequestor(XDisplay* x_display, |
28 Window x_window, | 30 XID x_window, |
29 Atom selection_name, | 31 XAtom selection_name, |
30 PlatformEventDispatcher* dispatcher) | 32 PlatformEventDispatcher* dispatcher) |
31 : x_display_(x_display), | 33 : x_display_(x_display), |
32 x_window_(x_window), | 34 x_window_(x_window), |
33 selection_name_(selection_name), | 35 selection_name_(selection_name), |
34 dispatcher_(dispatcher), | 36 dispatcher_(dispatcher), |
35 atom_cache_(x_display_, kAtomsToCache) { | 37 atom_cache_(x_display_, kAtomsToCache) { |
36 } | 38 } |
37 | 39 |
38 SelectionRequestor::~SelectionRequestor() {} | 40 SelectionRequestor::~SelectionRequestor() {} |
39 | 41 |
40 bool SelectionRequestor::PerformBlockingConvertSelection( | 42 bool SelectionRequestor::PerformBlockingConvertSelection( |
41 Atom target, | 43 XAtom target, |
42 scoped_refptr<base::RefCountedMemory>* out_data, | 44 scoped_refptr<base::RefCountedMemory>* out_data, |
43 size_t* out_data_items, | 45 size_t* out_data_items, |
44 Atom* out_type) { | 46 XAtom* out_type) { |
45 // The name of the property that we are either: | 47 // The name of the property that we are either: |
46 // - Passing as a parameter with the XConvertSelection() request. | 48 // - Passing as a parameter with the XConvertSelection() request. |
47 // OR | 49 // OR |
48 // - Asking the selection owner to set on |x_window_|. | 50 // - Asking the selection owner to set on |x_window_|. |
49 Atom property = atom_cache_.GetAtom(kChromeSelection); | 51 XAtom property = atom_cache_.GetAtom(kChromeSelection); |
50 | 52 |
51 XConvertSelection(x_display_, | 53 XConvertSelection(x_display_, |
52 selection_name_, | 54 selection_name_, |
53 target, | 55 target, |
54 property, | 56 property, |
55 x_window_, | 57 x_window_, |
56 CurrentTime); | 58 CurrentTime); |
57 | 59 |
58 // Now that we've thrown our message off to the X11 server, we block waiting | 60 // Now that we've thrown our message off to the X11 server, we block waiting |
59 // for a response. | 61 // for a response. |
60 PendingRequest pending_request(target); | 62 PendingRequest pending_request(target); |
61 BlockTillSelectionNotifyForRequest(&pending_request); | 63 BlockTillSelectionNotifyForRequest(&pending_request); |
62 | 64 |
63 bool success = false; | 65 bool success = false; |
64 if (pending_request.returned_property == property) { | 66 if (pending_request.returned_property == property) { |
65 success = ui::GetRawBytesOfProperty(x_window_, | 67 success = ui::GetRawBytesOfProperty(x_window_, |
66 pending_request.returned_property, | 68 pending_request.returned_property, |
67 out_data, out_data_items, out_type); | 69 out_data, out_data_items, out_type); |
68 } | 70 } |
69 if (pending_request.returned_property != None) | 71 if (pending_request.returned_property != None) |
70 XDeleteProperty(x_display_, x_window_, pending_request.returned_property); | 72 XDeleteProperty(x_display_, x_window_, pending_request.returned_property); |
71 return success; | 73 return success; |
72 } | 74 } |
73 | 75 |
74 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( | 76 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( |
75 Atom target, | 77 XAtom target, |
76 const std::vector< ::Atom>& parameter) { | 78 const std::vector<XAtom>& parameter) { |
77 SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); | 79 SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); |
78 PerformBlockingConvertSelection(target, NULL, NULL, NULL); | 80 PerformBlockingConvertSelection(target, NULL, NULL, NULL); |
79 } | 81 } |
80 | 82 |
81 SelectionData SelectionRequestor::RequestAndWaitForTypes( | 83 SelectionData SelectionRequestor::RequestAndWaitForTypes( |
82 const std::vector< ::Atom>& types) { | 84 const std::vector<XAtom>& types) { |
83 for (std::vector< ::Atom>::const_iterator it = types.begin(); | 85 for (std::vector<XAtom>::const_iterator it = types.begin(); |
84 it != types.end(); ++it) { | 86 it != types.end(); ++it) { |
85 scoped_refptr<base::RefCountedMemory> data; | 87 scoped_refptr<base::RefCountedMemory> data; |
86 ::Atom type = None; | 88 XAtom type = None; |
87 if (PerformBlockingConvertSelection(*it, | 89 if (PerformBlockingConvertSelection(*it, |
88 &data, | 90 &data, |
89 NULL, | 91 NULL, |
90 &type) && | 92 &type) && |
91 type == *it) { | 93 type == *it) { |
92 return SelectionData(type, data); | 94 return SelectionData(type, data); |
93 } | 95 } |
94 } | 96 } |
95 | 97 |
96 return SelectionData(); | 98 return SelectionData(); |
97 } | 99 } |
98 | 100 |
99 void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) { | 101 void SelectionRequestor::OnSelectionNotify(const XEvent& event) { |
100 // Find the PendingRequest for the corresponding XConvertSelection call. If | 102 // Find the PendingRequest for the corresponding XConvertSelection call. If |
101 // there are multiple pending requests on the same target, satisfy them in | 103 // there are multiple pending requests on the same target, satisfy them in |
102 // FIFO order. | 104 // FIFO order. |
103 PendingRequest* request_notified = NULL; | 105 PendingRequest* request_notified = NULL; |
104 if (selection_name_ == event.selection) { | 106 if (selection_name_ == event.xselection.selection) { |
105 for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin(); | 107 for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin(); |
106 iter != pending_requests_.end(); ++iter) { | 108 iter != pending_requests_.end(); ++iter) { |
107 PendingRequest* request = *iter; | 109 PendingRequest* request = *iter; |
108 if (request->returned) | 110 if (request->returned) |
109 continue; | 111 continue; |
110 if (request->target != event.target) | 112 if (request->target != event.xselection.target) |
111 continue; | 113 continue; |
112 request_notified = request; | 114 request_notified = request; |
113 break; | 115 break; |
114 } | 116 } |
115 } | 117 } |
116 | 118 |
117 // This event doesn't correspond to any XConvertSelection calls that we | 119 // This event doesn't correspond to any XConvertSelection calls that we |
118 // issued in PerformBlockingConvertSelection. This shouldn't happen, but any | 120 // issued in PerformBlockingConvertSelection. This shouldn't happen, but any |
119 // client can send any message, so it can happen. | 121 // client can send any message, so it can happen. |
| 122 XAtom returned_property = event.xselection.property; |
120 if (!request_notified) { | 123 if (!request_notified) { |
121 // ICCCM requires us to delete the property passed into SelectionNotify. If | 124 // ICCCM requires us to delete the property passed into SelectionNotify. If |
122 // |request_notified| is true, the property will be deleted when the run | 125 // |request_notified| is true, the property will be deleted when the run |
123 // loop has quit. | 126 // loop has quit. |
124 if (event.property != None) | 127 if (returned_property != None) |
125 XDeleteProperty(x_display_, x_window_, event.property); | 128 XDeleteProperty(x_display_, x_window_, returned_property); |
126 return; | 129 return; |
127 } | 130 } |
128 | 131 |
129 request_notified->returned_property = event.property; | 132 request_notified->returned_property = returned_property; |
130 request_notified->returned = true; | 133 request_notified->returned = true; |
131 | 134 |
132 if (!request_notified->quit_closure.is_null()) | 135 if (!request_notified->quit_closure.is_null()) |
133 request_notified->quit_closure.Run(); | 136 request_notified->quit_closure.Run(); |
134 } | 137 } |
135 | 138 |
136 void SelectionRequestor::BlockTillSelectionNotifyForRequest( | 139 void SelectionRequestor::BlockTillSelectionNotifyForRequest( |
137 PendingRequest* request) { | 140 PendingRequest* request) { |
138 pending_requests_.push_back(request); | 141 pending_requests_.push_back(request); |
139 | 142 |
(...skipping 24 matching lines...) Expand all Loading... |
164 if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse) | 167 if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse) |
165 break; | 168 break; |
166 } | 169 } |
167 } | 170 } |
168 | 171 |
169 DCHECK(!pending_requests_.empty()); | 172 DCHECK(!pending_requests_.empty()); |
170 DCHECK_EQ(request, pending_requests_.back()); | 173 DCHECK_EQ(request, pending_requests_.back()); |
171 pending_requests_.pop_back(); | 174 pending_requests_.pop_back(); |
172 } | 175 } |
173 | 176 |
174 SelectionRequestor::PendingRequest::PendingRequest(Atom target) | 177 SelectionRequestor::PendingRequest::PendingRequest(XAtom target) |
175 : target(target), | 178 : target(target), |
176 returned_property(None), | 179 returned_property(None), |
177 returned(false) { | 180 returned(false) { |
178 } | 181 } |
179 | 182 |
180 SelectionRequestor::PendingRequest::~PendingRequest() { | 183 SelectionRequestor::PendingRequest::~PendingRequest() { |
181 } | 184 } |
182 | 185 |
183 } // namespace ui | 186 } // namespace ui |
OLD | NEW |