blob: 8be12c67bd456abfa1af6429346ca963f18a315e [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <vector>
#include "base/callback.h"
#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/base/ui_base_export.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
namespace ui {
class PlatformEventDispatcher;
class SelectionData;
// Requests and later receives data from the X11 server through the selection
// system.
// X11 uses a system called "selections" to implement clipboards and drag and
// drop. This class interprets messages from the stateful selection request
// API. SelectionRequestor should only deal with the X11 details; it does not
// implement per-component fast-paths.
class UI_BASE_EXPORT SelectionRequestor {
SelectionRequestor(XDisplay* xdisplay,
XID xwindow,
PlatformEventDispatcher* dispatcher);
// Does the work of requesting |target| from |selection|, spinning up the
// nested message loop, and reading the resulting data back. The result is
// stored in |out_data|.
// |out_data_items| is the length of |out_data| in |out_type| items.
bool PerformBlockingConvertSelection(
XAtom selection,
XAtom target,
scoped_refptr<base::RefCountedMemory>* out_data,
size_t* out_data_items,
XAtom* out_type);
// Requests |target| from |selection|, passing |parameter| as a parameter to
// XConvertSelection().
void PerformBlockingConvertSelectionWithParameter(
XAtom selection,
XAtom target,
const std::vector<XAtom>& parameter);
// Returns the first of |types| offered by the current owner of |selection|.
// Returns an empty SelectionData object if none of |types| are available.
SelectionData RequestAndWaitForTypes(XAtom selection,
const std::vector<XAtom>& types);
// It is our owner's responsibility to plumb X11 SelectionNotify events on
// |xwindow_| to us.
void OnSelectionNotify(const XEvent& event);
// Returns true if SelectionOwner can process the XChangeProperty event,
// |event|.
bool CanDispatchPropertyEvent(const XEvent& event);
void OnPropertyEvent(const XEvent& event);
friend class SelectionRequestorTest;
// A request that has been issued.
struct Request {
Request(XAtom selection, XAtom target, base::TimeTicks timeout);
// The target and selection requested in the XConvertSelection() request.
// Used for error detection.
XAtom selection;
XAtom target;
// Whether the result of the XConvertSelection() request is being sent
// incrementally.
bool data_sent_incrementally;
// The result data for the XConvertSelection() request.
std::vector<scoped_refptr<base::RefCountedMemory> > out_data;
size_t out_data_items;
XAtom out_type;
// Whether the XConvertSelection() request was successful.
bool success;
// The time when the request should be aborted.
base::TimeTicks timeout;
// Called to terminate the nested message loop.
base::Closure quit_closure;
// True if the request is complete.
bool completed;
// Aborts requests which have timed out.
void AbortStaleRequests();
// Mark |request| as completed. If the current request is completed, converts
// the selection for the next request.
void CompleteRequest(size_t index, bool success);
// Converts the selection for the request at |current_request_index_|.
void ConvertSelectionForCurrentRequest();
// Blocks till SelectionNotify is received for the target specified in
// |request|.
void BlockTillSelectionNotifyForRequest(Request* request);
// Returns the request at |current_request_index_| or NULL if there isn't any.
Request* GetCurrentRequest();
// Our X11 state.
XDisplay* x_display_;
XID x_window_;
// The property on |x_window_| set by the selection owner with the value of
// the selection.
XAtom x_property_;
// Dispatcher which handles SelectionNotify and SelectionRequest for
// |selection_name_|. PerformBlockingConvertSelection() calls the
// dispatcher directly if PerformBlockingConvertSelection() is called after
// the PlatformEventSource is destroyed.
// Not owned.
PlatformEventDispatcher* dispatcher_;
// In progress requests. Requests are added to the list at the start of
// PerformBlockingConvertSelection() and are removed and destroyed right
// before the method terminates.
std::vector<Request*> requests_;
// The index of the currently active request in |requests_|. The active
// request is the request for which XConvertSelection() has been
// called and for which we are waiting for a SelectionNotify response.
size_t current_request_index_;
// Used to abort requests if the selection owner takes too long to respond.
base::RepeatingTimer abort_timer_;
X11AtomCache atom_cache_;
} // namespace ui