• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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