• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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