Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / ui / base / x / selection_owner.cc
blobc30187e1991e279ef22bcaf156f4f707fc59a8cb
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
3 // found in the LICENSE file.
5 #include "ui/base/x/selection_owner.h"
7 #include <X11/Xlib.h>
8 #include <X11/Xatom.h>
10 #include "base/logging.h"
11 #include "ui/base/x/selection_utils.h"
12 #include "ui/base/x/x11_util.h"
14 namespace ui {
16 namespace {
18 const char kAtomPair[] = "ATOM_PAIR";
19 const char kMultiple[] = "MULTIPLE";
20 const char kSaveTargets[] = "SAVE_TARGETS";
21 const char kTargets[] = "TARGETS";
23 const char* kAtomsToCache[] = {
24 kAtomPair,
25 kMultiple,
26 kSaveTargets,
27 kTargets,
28 NULL
31 // Gets the value of an atom pair array property. On success, true is returned
32 // and the value is stored in |value|.
33 bool GetAtomPairArrayProperty(XID window,
34 Atom property,
35 std::vector<std::pair<Atom,Atom> >* value) {
36 Atom type = None;
37 int format = 0; // size in bits of each item in 'property'
38 unsigned long num_items = 0;
39 unsigned char* properties = NULL;
40 unsigned long remaining_bytes = 0;
42 int result = XGetWindowProperty(gfx::GetXDisplay(),
43 window,
44 property,
45 0, // offset into property data to
46 // read
47 (~0L), // entire array
48 False, // deleted
49 AnyPropertyType,
50 &type,
51 &format,
52 &num_items,
53 &remaining_bytes,
54 &properties);
56 if (result != Success)
57 return false;
59 // GTK does not require |type| to be kAtomPair.
60 if (format != 32 || num_items % 2 != 0) {
61 XFree(properties);
62 return false;
65 Atom* atom_properties = reinterpret_cast<Atom*>(properties);
66 value->clear();
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]));
69 XFree(properties);
70 return true;
73 } // namespace
75 SelectionOwner::SelectionOwner(Display* x_display,
76 Window x_window,
77 Atom selection_name)
78 : x_display_(x_display),
79 x_window_(x_window),
80 selection_name_(selection_name),
81 atom_cache_(x_display_, kAtomsToCache) {
84 SelectionOwner::~SelectionOwner() {
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()
87 // because we don't want to do this indiscriminately.
88 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_)
89 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
92 void SelectionOwner::RetrieveTargets(std::vector<Atom>* targets) {
93 for (SelectionFormatMap::const_iterator it = format_map_.begin();
94 it != format_map_.end(); ++it) {
95 targets->push_back(it->first);
99 void SelectionOwner::TakeOwnershipOfSelection(
100 const SelectionFormatMap& data) {
101 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime);
103 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) {
104 // The X server agrees that we are the selection owner. Commit our data.
105 format_map_ = data;
109 void SelectionOwner::ClearSelectionOwner() {
110 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
111 format_map_ = SelectionFormatMap();
114 void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) {
115 // Incrementally build our selection. By default this is a refusal, and we'll
116 // override the parts indicating success in the different cases.
117 XEvent reply;
118 reply.xselection.type = SelectionNotify;
119 reply.xselection.requestor = event.requestor;
120 reply.xselection.selection = event.selection;
121 reply.xselection.target = event.target;
122 reply.xselection.property = None; // Indicates failure
123 reply.xselection.time = event.time;
125 if (event.target == atom_cache_.GetAtom(kMultiple)) {
126 // The contents of |event.property| should be a list of
127 // <target,property> pairs.
128 std::vector<std::pair<Atom,Atom> > conversions;
129 if (GetAtomPairArrayProperty(event.requestor,
130 event.property,
131 &conversions)) {
132 std::vector<Atom> conversion_results;
133 for (size_t i = 0; i < conversions.size(); ++i) {
134 bool conversion_successful = ProcessTarget(conversions[i].first,
135 event.requestor,
136 conversions[i].second);
137 conversion_results.push_back(conversions[i].first);
138 conversion_results.push_back(
139 conversion_successful ? conversions[i].second : None);
142 // Set the property to indicate which conversions succeeded. This matches
143 // what GTK does.
144 XChangeProperty(
145 x_display_,
146 event.requestor,
147 event.property,
148 atom_cache_.GetAtom(kAtomPair),
150 PropModeReplace,
151 reinterpret_cast<const unsigned char*>(&conversion_results.front()),
152 conversion_results.size());
154 reply.xselection.property = event.property;
156 } else {
157 if (ProcessTarget(event.target, event.requestor, event.property))
158 reply.xselection.property = event.property;
161 // Send off the reply.
162 XSendEvent(x_display_, event.requestor, False, 0, &reply);
165 void SelectionOwner::OnSelectionClear(const XSelectionClearEvent& event) {
166 DLOG(ERROR) << "SelectionClear";
168 // TODO(erg): If we receive a SelectionClear event while we're handling data,
169 // we need to delay clearing.
172 bool SelectionOwner::ProcessTarget(Atom target,
173 ::Window requestor,
174 ::Atom property) {
175 Atom multiple_atom = atom_cache_.GetAtom(kMultiple);
176 Atom save_targets_atom = atom_cache_.GetAtom(kSaveTargets);
177 Atom targets_atom = atom_cache_.GetAtom(kTargets);
179 if (target == multiple_atom || target == save_targets_atom)
180 return false;
182 if (target == targets_atom) {
183 // We have been asked for TARGETS. Send an atom array back with the data
184 // types we support.
185 std::vector<Atom> targets;
186 targets.push_back(targets_atom);
187 targets.push_back(save_targets_atom);
188 targets.push_back(multiple_atom);
189 RetrieveTargets(&targets);
191 XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
192 PropModeReplace,
193 reinterpret_cast<unsigned char*>(&targets.front()),
194 targets.size());
195 return true;
196 } else {
197 // Try to find the data type in map.
198 SelectionFormatMap::const_iterator it = format_map_.find(target);
199 if (it != format_map_.end()) {
200 XChangeProperty(x_display_, requestor, property, target, 8,
201 PropModeReplace,
202 const_cast<unsigned char*>(
203 reinterpret_cast<const unsigned char*>(
204 it->second->front())),
205 it->second->size());
206 return true;
208 // I would put error logging here, but GTK ignores TARGETS and spams us
209 // looking for its own internal types.
211 return false;
214 } // namespace ui