| 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 |