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