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 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 37 SelectionOwner::~SelectionOwner() { 38 Clear(); 39 } 40 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 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 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 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 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