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