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 <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/Xatom.h> | 8 #include <X11/Xatom.h> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 kAtomPair, | 24 kAtomPair, |
25 kMultiple, | 25 kMultiple, |
26 kSaveTargets, | 26 kSaveTargets, |
27 kTargets, | 27 kTargets, |
28 NULL | 28 NULL |
29 }; | 29 }; |
30 | 30 |
31 // Gets the value of an atom pair array property. On success, true is returned | 31 // Gets the value of an atom pair array property. On success, true is returned |
32 // and the value is stored in |value|. | 32 // and the value is stored in |value|. |
33 bool GetAtomPairArrayProperty(XID window, | 33 bool GetAtomPairArrayProperty(XID window, |
34 Atom property, | 34 XAtom property, |
35 std::vector<std::pair<Atom,Atom> >* value) { | 35 std::vector<std::pair<XAtom,XAtom> >* value) { |
36 Atom type = None; | 36 XAtom type = None; |
37 int format = 0; // size in bits of each item in 'property' | 37 int format = 0; // size in bits of each item in 'property' |
38 unsigned long num_items = 0; | 38 unsigned long num_items = 0; |
39 unsigned char* properties = NULL; | 39 unsigned char* properties = NULL; |
40 unsigned long remaining_bytes = 0; | 40 unsigned long remaining_bytes = 0; |
41 | 41 |
42 int result = XGetWindowProperty(gfx::GetXDisplay(), | 42 int result = XGetWindowProperty(gfx::GetXDisplay(), |
43 window, | 43 window, |
44 property, | 44 property, |
45 0, // offset into property data to | 45 0, // offset into property data to |
46 // read | 46 // read |
47 (~0L), // entire array | 47 (~0L), // entire array |
48 False, // deleted | 48 False, // deleted |
49 AnyPropertyType, | 49 AnyPropertyType, |
50 &type, | 50 &type, |
51 &format, | 51 &format, |
52 &num_items, | 52 &num_items, |
53 &remaining_bytes, | 53 &remaining_bytes, |
54 &properties); | 54 &properties); |
55 | 55 |
56 if (result != Success) | 56 if (result != Success) |
57 return false; | 57 return false; |
58 | 58 |
59 // GTK does not require |type| to be kAtomPair. | 59 // GTK does not require |type| to be kAtomPair. |
60 if (format != 32 || num_items % 2 != 0) { | 60 if (format != 32 || num_items % 2 != 0) { |
61 XFree(properties); | 61 XFree(properties); |
62 return false; | 62 return false; |
63 } | 63 } |
64 | 64 |
65 Atom* atom_properties = reinterpret_cast<Atom*>(properties); | 65 XAtom* atom_properties = reinterpret_cast<XAtom*>(properties); |
66 value->clear(); | 66 value->clear(); |
67 for (size_t i = 0; i < num_items; i+=2) | 67 for (size_t i = 0; i < num_items; i+=2) |
68 value->push_back(std::make_pair(atom_properties[i], atom_properties[i+1])); | 68 value->push_back(std::make_pair(atom_properties[i], atom_properties[i+1])); |
69 XFree(properties); | 69 XFree(properties); |
70 return true; | 70 return true; |
71 } | 71 } |
72 | 72 |
73 } // namespace | 73 } // namespace |
74 | 74 |
75 SelectionOwner::SelectionOwner(Display* x_display, | 75 SelectionOwner::SelectionOwner(XDisplay* x_display, |
76 Window x_window, | 76 XID x_window, |
77 Atom selection_name) | 77 XAtom selection_name) |
78 : x_display_(x_display), | 78 : x_display_(x_display), |
79 x_window_(x_window), | 79 x_window_(x_window), |
80 selection_name_(selection_name), | 80 selection_name_(selection_name), |
81 atom_cache_(x_display_, kAtomsToCache) { | 81 atom_cache_(x_display_, kAtomsToCache) { |
82 } | 82 } |
83 | 83 |
84 SelectionOwner::~SelectionOwner() { | 84 SelectionOwner::~SelectionOwner() { |
85 // If we are the selection owner, we need to release the selection so we | 85 // If we are the selection owner, we need to release the selection so we |
86 // don't receive further events. However, we don't call ClearSelectionOwner() | 86 // don't receive further events. However, we don't call ClearSelectionOwner() |
87 // because we don't want to do this indiscriminately. | 87 // because we don't want to do this indiscriminately. |
88 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) | 88 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) |
89 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); | 89 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); |
90 } | 90 } |
91 | 91 |
92 void SelectionOwner::RetrieveTargets(std::vector<Atom>* targets) { | 92 void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { |
93 for (SelectionFormatMap::const_iterator it = format_map_.begin(); | 93 for (SelectionFormatMap::const_iterator it = format_map_.begin(); |
94 it != format_map_.end(); ++it) { | 94 it != format_map_.end(); ++it) { |
95 targets->push_back(it->first); | 95 targets->push_back(it->first); |
96 } | 96 } |
97 } | 97 } |
98 | 98 |
99 void SelectionOwner::TakeOwnershipOfSelection( | 99 void SelectionOwner::TakeOwnershipOfSelection( |
100 const SelectionFormatMap& data) { | 100 const SelectionFormatMap& data) { |
101 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); | 101 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); |
102 | 102 |
103 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { | 103 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { |
104 // The X server agrees that we are the selection owner. Commit our data. | 104 // The X server agrees that we are the selection owner. Commit our data. |
105 format_map_ = data; | 105 format_map_ = data; |
106 } | 106 } |
107 } | 107 } |
108 | 108 |
109 void SelectionOwner::ClearSelectionOwner() { | 109 void SelectionOwner::ClearSelectionOwner() { |
110 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); | 110 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); |
111 format_map_ = SelectionFormatMap(); | 111 format_map_ = SelectionFormatMap(); |
112 } | 112 } |
113 | 113 |
114 void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) { | 114 void SelectionOwner::OnSelectionRequest(const XEvent& event) { |
| 115 XID requestor = event.xselectionrequest.requestor; |
| 116 XAtom requested_target = event.xselectionrequest.target; |
| 117 XAtom requested_property = event.xselectionrequest.property; |
| 118 |
115 // Incrementally build our selection. By default this is a refusal, and we'll | 119 // Incrementally build our selection. By default this is a refusal, and we'll |
116 // override the parts indicating success in the different cases. | 120 // override the parts indicating success in the different cases. |
117 XEvent reply; | 121 XEvent reply; |
118 reply.xselection.type = SelectionNotify; | 122 reply.xselection.type = SelectionNotify; |
119 reply.xselection.requestor = event.requestor; | 123 reply.xselection.requestor = requestor; |
120 reply.xselection.selection = event.selection; | 124 reply.xselection.selection = event.xselectionrequest.selection; |
121 reply.xselection.target = event.target; | 125 reply.xselection.target = requested_target; |
122 reply.xselection.property = None; // Indicates failure | 126 reply.xselection.property = None; // Indicates failure |
123 reply.xselection.time = event.time; | 127 reply.xselection.time = event.xselectionrequest.time; |
124 | 128 |
125 if (event.target == atom_cache_.GetAtom(kMultiple)) { | 129 if (requested_target == atom_cache_.GetAtom(kMultiple)) { |
126 // The contents of |event.property| should be a list of | 130 // The contents of |requested_property| should be a list of |
127 // <target,property> pairs. | 131 // <target,property> pairs. |
128 std::vector<std::pair<Atom,Atom> > conversions; | 132 std::vector<std::pair<XAtom,XAtom> > conversions; |
129 if (GetAtomPairArrayProperty(event.requestor, | 133 if (GetAtomPairArrayProperty(requestor, |
130 event.property, | 134 requested_property, |
131 &conversions)) { | 135 &conversions)) { |
132 std::vector<Atom> conversion_results; | 136 std::vector<XAtom> conversion_results; |
133 for (size_t i = 0; i < conversions.size(); ++i) { | 137 for (size_t i = 0; i < conversions.size(); ++i) { |
134 bool conversion_successful = ProcessTarget(conversions[i].first, | 138 bool conversion_successful = ProcessTarget(conversions[i].first, |
135 event.requestor, | 139 requestor, |
136 conversions[i].second); | 140 conversions[i].second); |
137 conversion_results.push_back(conversions[i].first); | 141 conversion_results.push_back(conversions[i].first); |
138 conversion_results.push_back( | 142 conversion_results.push_back( |
139 conversion_successful ? conversions[i].second : None); | 143 conversion_successful ? conversions[i].second : None); |
140 } | 144 } |
141 | 145 |
142 // Set the property to indicate which conversions succeeded. This matches | 146 // Set the property to indicate which conversions succeeded. This matches |
143 // what GTK does. | 147 // what GTK does. |
144 XChangeProperty( | 148 XChangeProperty( |
145 x_display_, | 149 x_display_, |
146 event.requestor, | 150 requestor, |
147 event.property, | 151 requested_property, |
148 atom_cache_.GetAtom(kAtomPair), | 152 atom_cache_.GetAtom(kAtomPair), |
149 32, | 153 32, |
150 PropModeReplace, | 154 PropModeReplace, |
151 reinterpret_cast<const unsigned char*>(&conversion_results.front()), | 155 reinterpret_cast<const unsigned char*>(&conversion_results.front()), |
152 conversion_results.size()); | 156 conversion_results.size()); |
153 | 157 |
154 reply.xselection.property = event.property; | 158 reply.xselection.property = requested_property; |
155 } | 159 } |
156 } else { | 160 } else { |
157 if (ProcessTarget(event.target, event.requestor, event.property)) | 161 if (ProcessTarget(requested_target, requestor, requested_property)) |
158 reply.xselection.property = event.property; | 162 reply.xselection.property = requested_property; |
159 } | 163 } |
160 | 164 |
161 // Send off the reply. | 165 // Send off the reply. |
162 XSendEvent(x_display_, event.requestor, False, 0, &reply); | 166 XSendEvent(x_display_, requestor, False, 0, &reply); |
163 } | 167 } |
164 | 168 |
165 void SelectionOwner::OnSelectionClear(const XSelectionClearEvent& event) { | 169 void SelectionOwner::OnSelectionClear(const XEvent& event) { |
166 DLOG(ERROR) << "SelectionClear"; | 170 DLOG(ERROR) << "SelectionClear"; |
167 | 171 |
168 // TODO(erg): If we receive a SelectionClear event while we're handling data, | 172 // TODO(erg): If we receive a SelectionClear event while we're handling data, |
169 // we need to delay clearing. | 173 // we need to delay clearing. |
170 } | 174 } |
171 | 175 |
172 bool SelectionOwner::ProcessTarget(Atom target, | 176 bool SelectionOwner::ProcessTarget(XAtom target, |
173 ::Window requestor, | 177 XID requestor, |
174 ::Atom property) { | 178 XAtom property) { |
175 Atom multiple_atom = atom_cache_.GetAtom(kMultiple); | 179 XAtom multiple_atom = atom_cache_.GetAtom(kMultiple); |
176 Atom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); | 180 XAtom save_targets_atom = atom_cache_.GetAtom(kSaveTargets); |
177 Atom targets_atom = atom_cache_.GetAtom(kTargets); | 181 XAtom targets_atom = atom_cache_.GetAtom(kTargets); |
178 | 182 |
179 if (target == multiple_atom || target == save_targets_atom) | 183 if (target == multiple_atom || target == save_targets_atom) |
180 return false; | 184 return false; |
181 | 185 |
182 if (target == targets_atom) { | 186 if (target == targets_atom) { |
183 // We have been asked for TARGETS. Send an atom array back with the data | 187 // We have been asked for TARGETS. Send an atom array back with the data |
184 // types we support. | 188 // types we support. |
185 std::vector<Atom> targets; | 189 std::vector<XAtom> targets; |
186 targets.push_back(targets_atom); | 190 targets.push_back(targets_atom); |
187 targets.push_back(save_targets_atom); | 191 targets.push_back(save_targets_atom); |
188 targets.push_back(multiple_atom); | 192 targets.push_back(multiple_atom); |
189 RetrieveTargets(&targets); | 193 RetrieveTargets(&targets); |
190 | 194 |
191 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, | 195 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, |
192 PropModeReplace, | 196 PropModeReplace, |
193 reinterpret_cast<unsigned char*>(&targets.front()), | 197 reinterpret_cast<unsigned char*>(&targets.front()), |
194 targets.size()); | 198 targets.size()); |
195 return true; | 199 return true; |
196 } else { | 200 } else { |
197 // Try to find the data type in map. | 201 // Try to find the data type in map. |
198 SelectionFormatMap::const_iterator it = format_map_.find(target); | 202 SelectionFormatMap::const_iterator it = format_map_.find(target); |
199 if (it != format_map_.end()) { | 203 if (it != format_map_.end()) { |
200 XChangeProperty(x_display_, requestor, property, target, 8, | 204 XChangeProperty(x_display_, requestor, property, target, 8, |
201 PropModeReplace, | 205 PropModeReplace, |
202 const_cast<unsigned char*>( | 206 const_cast<unsigned char*>( |
203 reinterpret_cast<const unsigned char*>( | 207 reinterpret_cast<const unsigned char*>( |
204 it->second->front())), | 208 it->second->front())), |
205 it->second->size()); | 209 it->second->size()); |
206 return true; | 210 return true; |
207 } | 211 } |
208 // I would put error logging here, but GTK ignores TARGETS and spams us | 212 // I would put error logging here, but GTK ignores TARGETS and spams us |
209 // looking for its own internal types. | 213 // looking for its own internal types. |
210 } | 214 } |
211 return false; | 215 return false; |
212 } | 216 } |
213 | 217 |
214 } // namespace ui | 218 } // namespace ui |
215 | |
OLD | NEW |