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 #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