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 #ifndef UI_BASE_X_SELECTION_REQUESTOR_H_ 6 #define UI_BASE_X_SELECTION_REQUESTOR_H_ 7 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/callback.h" 12 #include "base/event_types.h" 13 #include "base/memory/ref_counted_memory.h" 14 #include "base/time/time.h" 15 #include "base/timer/timer.h" 16 #include "ui/base/ui_base_export.h" 17 #include "ui/gfx/x/x11_atom_cache.h" 18 #include "ui/gfx/x/x11_types.h" 19 20 namespace ui { 21 class PlatformEventDispatcher; 22 class SelectionData; 23 24 // Requests and later receives data from the X11 server through the selection 25 // system. 26 // 27 // X11 uses a system called "selections" to implement clipboards and drag and 28 // drop. This class interprets messages from the stateful selection request 29 // API. SelectionRequestor should only deal with the X11 details; it does not 30 // implement per-component fast-paths. 31 class UI_BASE_EXPORT SelectionRequestor { 32 public: 33 SelectionRequestor(XDisplay* xdisplay, 34 XID xwindow, 35 PlatformEventDispatcher* dispatcher); 36 ~SelectionRequestor(); 37 38 // Does the work of requesting |target| from |selection|, spinning up the 39 // nested message loop, and reading the resulting data back. The result is 40 // stored in |out_data|. 41 // |out_data_items| is the length of |out_data| in |out_type| items. 42 bool PerformBlockingConvertSelection( 43 XAtom selection, 44 XAtom target, 45 scoped_refptr<base::RefCountedMemory>* out_data, 46 size_t* out_data_items, 47 XAtom* out_type); 48 49 // Requests |target| from |selection|, passing |parameter| as a parameter to 50 // XConvertSelection(). 51 void PerformBlockingConvertSelectionWithParameter( 52 XAtom selection, 53 XAtom target, 54 const std::vector<XAtom>& parameter); 55 56 // Returns the first of |types| offered by the current owner of |selection|. 57 // Returns an empty SelectionData object if none of |types| are available. 58 SelectionData RequestAndWaitForTypes(XAtom selection, 59 const std::vector<XAtom>& types); 60 61 // It is our owner's responsibility to plumb X11 SelectionNotify events on 62 // |xwindow_| to us. 63 void OnSelectionNotify(const XEvent& event); 64 65 // Returns true if SelectionOwner can process the XChangeProperty event, 66 // |event|. 67 bool CanDispatchPropertyEvent(const XEvent& event); 68 69 void OnPropertyEvent(const XEvent& event); 70 71 private: 72 friend class SelectionRequestorTest; 73 74 // A request that has been issued. 75 struct Request { 76 Request(XAtom selection, XAtom target, base::TimeTicks timeout); 77 ~Request(); 78 79 // The target and selection requested in the XConvertSelection() request. 80 // Used for error detection. 81 XAtom selection; 82 XAtom target; 83 84 // Whether the result of the XConvertSelection() request is being sent 85 // incrementally. 86 bool data_sent_incrementally; 87 88 // The result data for the XConvertSelection() request. 89 std::vector<scoped_refptr<base::RefCountedMemory> > out_data; 90 size_t out_data_items; 91 XAtom out_type; 92 93 // Whether the XConvertSelection() request was successful. 94 bool success; 95 96 // The time when the request should be aborted. 97 base::TimeTicks timeout; 98 99 // Called to terminate the nested message loop. 100 base::Closure quit_closure; 101 102 // True if the request is complete. 103 bool completed; 104 }; 105 106 // Aborts requests which have timed out. 107 void AbortStaleRequests(); 108 109 // Mark |request| as completed. If the current request is completed, converts 110 // the selection for the next request. 111 void CompleteRequest(size_t index, bool success); 112 113 // Converts the selection for the request at |current_request_index_|. 114 void ConvertSelectionForCurrentRequest(); 115 116 // Blocks till SelectionNotify is received for the target specified in 117 // |request|. 118 void BlockTillSelectionNotifyForRequest(Request* request); 119 120 // Returns the request at |current_request_index_| or NULL if there isn't any. 121 Request* GetCurrentRequest(); 122 123 // Our X11 state. 124 XDisplay* x_display_; 125 XID x_window_; 126 127 // The property on |x_window_| set by the selection owner with the value of 128 // the selection. 129 XAtom x_property_; 130 131 // Dispatcher which handles SelectionNotify and SelectionRequest for 132 // |selection_name_|. PerformBlockingConvertSelection() calls the 133 // dispatcher directly if PerformBlockingConvertSelection() is called after 134 // the PlatformEventSource is destroyed. 135 // Not owned. 136 PlatformEventDispatcher* dispatcher_; 137 138 // In progress requests. Requests are added to the list at the start of 139 // PerformBlockingConvertSelection() and are removed and destroyed right 140 // before the method terminates. 141 std::vector<Request*> requests_; 142 143 // The index of the currently active request in |requests_|. The active 144 // request is the request for which XConvertSelection() has been 145 // called and for which we are waiting for a SelectionNotify response. 146 size_t current_request_index_; 147 148 // Used to abort requests if the selection owner takes too long to respond. 149 base::RepeatingTimer<SelectionRequestor> abort_timer_; 150 151 X11AtomCache atom_cache_; 152 153 DISALLOW_COPY_AND_ASSIGN(SelectionRequestor); 154 }; 155 156 } // namespace ui 157 158 #endif // UI_BASE_X_SELECTION_REQUESTOR_H_ 159