Home | History | Annotate | Download | only in x
      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_requestor.h"
      6 
      7 #include "base/message_loop/message_pump_aurax11.h"
      8 #include "base/run_loop.h"
      9 #include "ui/base/x/selection_utils.h"
     10 #include "ui/base/x/x11_util.h"
     11 
     12 namespace ui {
     13 
     14 namespace {
     15 
     16 const char kChromeSelection[] = "CHROME_SELECTION";
     17 
     18 const char* kAtomsToCache[] = {
     19   kChromeSelection,
     20   NULL
     21 };
     22 
     23 }  // namespace
     24 
     25 SelectionRequestor::SelectionRequestor(Display* x_display,
     26                                        Window x_window,
     27                                        Atom selection_name)
     28     : x_display_(x_display),
     29       x_window_(x_window),
     30       in_nested_loop_(false),
     31       selection_name_(selection_name),
     32       current_target_(None),
     33       returned_property_(None),
     34       atom_cache_(x_display_, kAtomsToCache) {
     35 }
     36 
     37 SelectionRequestor::~SelectionRequestor() {}
     38 
     39 bool SelectionRequestor::PerformBlockingConvertSelection(
     40     Atom target,
     41     scoped_refptr<base::RefCountedMemory>* out_data,
     42     size_t* out_data_bytes,
     43     size_t* out_data_items,
     44     Atom* out_type) {
     45   // The name of the property we're asking to be set on |x_window_|.
     46   Atom property_to_set = atom_cache_.GetAtom(kChromeSelection);
     47 
     48   XConvertSelection(x_display_,
     49                     selection_name_,
     50                     target,
     51                     property_to_set,
     52                     x_window_,
     53                     CurrentTime);
     54 
     55   // Now that we've thrown our message off to the X11 server, we block waiting
     56   // for a response.
     57   base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
     58   base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
     59   base::RunLoop run_loop(base::MessagePumpAuraX11::Current());
     60 
     61   current_target_ = target;
     62   in_nested_loop_ = true;
     63   quit_closure_ = run_loop.QuitClosure();
     64   run_loop.Run();
     65   in_nested_loop_ = false;
     66   current_target_ = None;
     67 
     68   if (returned_property_ != property_to_set)
     69     return false;
     70 
     71   return ui::GetRawBytesOfProperty(x_window_, returned_property_,
     72                                    out_data, out_data_bytes, out_data_items,
     73                                    out_type);
     74 }
     75 
     76 SelectionData SelectionRequestor::RequestAndWaitForTypes(
     77     const std::vector< ::Atom>& types) {
     78   for (std::vector< ::Atom>::const_iterator it = types.begin();
     79        it != types.end(); ++it) {
     80     scoped_refptr<base::RefCountedMemory> data;
     81     size_t data_bytes = 0;
     82     ::Atom type = None;
     83     if (PerformBlockingConvertSelection(*it,
     84                                         &data,
     85                                         &data_bytes,
     86                                         NULL,
     87                                         &type) &&
     88         type == *it) {
     89       return SelectionData(type, data);
     90     }
     91   }
     92 
     93   return SelectionData();
     94 }
     95 
     96 void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) {
     97   if (!in_nested_loop_) {
     98     // This shouldn't happen; we're not waiting on the X server for data, but
     99     // any client can send any message...
    100     return;
    101   }
    102 
    103   if (selection_name_ == event.selection &&
    104       current_target_ == event.target) {
    105     returned_property_ = event.property;
    106   } else {
    107     // I am assuming that if some other client sent us a message after we've
    108     // asked for data, but it's malformed, we should just treat as if they sent
    109     // us an error message.
    110     returned_property_ = None;
    111   }
    112 
    113   quit_closure_.Run();
    114 }
    115 
    116 }  // namespace ui
    117