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.
4
5 #include "ui/base/x/selection_owner.h"
6
7 #include <X11/Xlib.h>
8 #include <X11/Xatom.h>
9
10 #include "base/logging.h"
11 #include "ui/base/x/selection_utils.h"
12
13 namespace ui {
14
15 namespace {
16
17 const char kMultiple[] = "MULTIPLE";
18 const char kTargets[] = "TARGETS";
19
20 const char* kAtomsToCache[] = {
21 kMultiple,
22 kTargets,
23 NULL
24 };
25
26 } // namespace
27
SelectionOwner(Display * x_display,Window x_window,Atom selection_name)28 SelectionOwner::SelectionOwner(Display* x_display,
29 Window x_window,
30 Atom selection_name)
31 : x_display_(x_display),
32 x_window_(x_window),
33 selection_name_(selection_name),
34 atom_cache_(x_display_, kAtomsToCache) {
35 }
36
~SelectionOwner()37 SelectionOwner::~SelectionOwner() {
38 Clear();
39 }
40
RetrieveTargets(std::vector<Atom> * targets)41 void SelectionOwner::RetrieveTargets(std::vector<Atom>* targets) {
42 targets->clear();
43 for (SelectionFormatMap::const_iterator it = format_map_.begin();
44 it != format_map_.end(); ++it) {
45 targets->push_back(it->first);
46 }
47 }
48
TakeOwnershipOfSelection(const SelectionFormatMap & data)49 void SelectionOwner::TakeOwnershipOfSelection(
50 const SelectionFormatMap& data) {
51 XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime);
52
53 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) {
54 // The X server agrees that we are the selection owner. Commit our data.
55 format_map_ = data;
56 }
57 }
58
Clear()59 void SelectionOwner::Clear() {
60 if (XGetSelectionOwner(x_display_, selection_name_) == x_window_)
61 XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
62
63 format_map_ = SelectionFormatMap();
64 }
65
OnSelectionRequest(const XSelectionRequestEvent & event)66 void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) {
67 // Incrementally build our selection. By default this is a refusal, and we'll
68 // override the parts indicating success in the different cases.
69 XEvent reply;
70 reply.xselection.type = SelectionNotify;
71 reply.xselection.requestor = event.requestor;
72 reply.xselection.selection = event.selection;
73 reply.xselection.target = event.target;
74 reply.xselection.property = None; // Indicates failure
75 reply.xselection.time = event.time;
76
77 // Get the proper selection.
78 Atom targets_atom = atom_cache_.GetAtom(kTargets);
79 if (event.target == targets_atom) {
80 // We have been asked for TARGETS. Send an atom array back with the data
81 // types we support.
82 std::vector<Atom> targets;
83 targets.push_back(targets_atom);
84 RetrieveTargets(&targets);
85
86 XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM, 32,
87 PropModeReplace,
88 reinterpret_cast<unsigned char*>(&targets.front()),
89 targets.size());
90 reply.xselection.property = event.property;
91 } else if (event.target == atom_cache_.GetAtom(kMultiple)) {
92 // TODO(erg): Theoretically, the spec claims I'm supposed to handle the
93 // MULTIPLE case, but I haven't seen it in the wild yet.
94 NOTIMPLEMENTED();
95 } else {
96 // Try to find the data type in map.
97 SelectionFormatMap::const_iterator it =
98 format_map_.find(event.target);
99 if (it != format_map_.end()) {
100 XChangeProperty(x_display_, event.requestor, event.property,
101 event.target, 8,
102 PropModeReplace,
103 const_cast<unsigned char*>(
104 reinterpret_cast<const unsigned char*>(
105 it->second->front())),
106 it->second->size());
107 reply.xselection.property = event.property;
108 }
109 // I would put error logging here, but GTK ignores TARGETS and spams us
110 // looking for its own internal types.
111 }
112
113 // Send off the reply.
114 XSendEvent(x_display_, event.requestor, False, 0, &reply);
115 }
116
OnSelectionClear(const XSelectionClearEvent & event)117 void SelectionOwner::OnSelectionClear(const XSelectionClearEvent& event) {
118 DLOG(ERROR) << "SelectionClear";
119
120 // TODO(erg): If we receive a SelectionClear event while we're handling data,
121 // we need to delay clearing.
122 }
123
124 } // namespace ui
125
126