1// Copyright (c) 2012 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// Don't include this file from any .h files because it pulls in some X headers.
6
7#ifndef REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
8#define REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
9
10#include <X11/Xatom.h>
11#include <X11/Xlib.h>
12
13#include <set>
14#include <string>
15
16#include "base/basictypes.h"
17#include "base/callback_forward.h"
18#include "base/timer/timer.h"
19
20namespace remoting {
21
22// A class to allow manipulation of the X clipboard, using only X API calls.
23// This class is not thread-safe, so all its methods must be called on the
24// application's main event-processing thread.
25class XServerClipboard {
26 public:
27  // Called when new clipboard data has been received from the owner of the X
28  // selection (primary or clipboard).
29  // |mime_type| is the MIME type associated with the data. This will be one of
30  // the types listed in remoting/base/constants.h.
31  // |data| is the clipboard data from the associated X event, encoded with the
32  // specified MIME-type.
33  typedef base::Callback<void(const std::string& mime_type,
34                              const std::string& data)>
35      ClipboardChangedCallback;
36
37  XServerClipboard();
38  ~XServerClipboard();
39
40  // Start monitoring |display|'s selections, and invoke |callback| whenever
41  // their content changes. The caller must ensure |display| is still valid
42  // whenever any other methods are called on this object.
43  void Init(Display* display, const ClipboardChangedCallback& callback);
44
45  // Copy data to the X Clipboard.  This acquires ownership of the
46  // PRIMARY and CLIPBOARD selections.
47  void SetClipboard(const std::string& mime_type, const std::string& data);
48
49  // Process |event| if it is an X selection notification. The caller should
50  // invoke this for every event it receives from |display|.
51  void ProcessXEvent(XEvent* event);
52
53 private:
54  // Handlers called by ProcessXEvent() for each event type.
55  void OnSetSelectionOwnerNotify(Atom selection, Time timestamp);
56  void OnPropertyNotify(XEvent* event);
57  void OnSelectionNotify(XEvent* event);
58  void OnSelectionRequest(XEvent* event);
59  void OnSelectionClear(XEvent* event);
60
61  // Used by OnSelectionRequest() to respond to requests for details of our
62  // clipboard content. This is done by changing the property |property| of the
63  // |requestor| window (these values come from the XSelectionRequestEvent).
64  // |target| must be a string type (STRING or UTF8_STRING).
65  void SendTargetsResponse(Window requestor, Atom property);
66  void SendTimestampResponse(Window requestor, Atom property);
67  void SendStringResponse(Window requestor, Atom property, Atom target);
68
69  // Called by OnSelectionNotify() when the selection owner has replied to a
70  // request for information about a selection.
71  // |event| is the raw X event from the notification.
72  // |type|, |format| etc are the results from XGetWindowProperty(), or 0 if
73  // there is no associated data.
74  void HandleSelectionNotify(XSelectionEvent* event,
75                             Atom type,
76                             int format,
77                             int item_count,
78                             void* data);
79
80  // These methods return true if selection processing is complete, false
81  // otherwise. They are called from HandleSelectionNotify(), and take the same
82  // arguments.
83  bool HandleSelectionTargetsEvent(XSelectionEvent* event,
84                                   int format,
85                                   int item_count,
86                                   void* data);
87  bool HandleSelectionStringEvent(XSelectionEvent* event,
88                                  int format,
89                                  int item_count,
90                                  void* data);
91
92  // Notify the registered callback of new clipboard text.
93  void NotifyClipboardText(const std::string& text);
94
95  // These methods trigger the X server or selection owner to send back an
96  // event containing the requested information.
97  void RequestSelectionTargets(Atom selection);
98  void RequestSelectionString(Atom selection, Atom target);
99
100  // Assert ownership of the specified |selection|.
101  void AssertSelectionOwnership(Atom selection);
102  bool IsSelectionOwner(Atom selection);
103
104  // Stores the Display* supplied to Init().
105  Display* display_;
106
107  // Window through which clipboard events are received, or BadValue if the
108  // window could not be created.
109  Window clipboard_window_;
110
111  // The event base returned by XFixesQueryExtension(). If XFixes is
112  // unavailable, the clipboard window will not be created, and no
113  // event-processing will take place.
114  int xfixes_event_base_;
115
116  // Cached atoms for various strings, initialized during Init().
117  Atom clipboard_atom_;
118  Atom large_selection_atom_;
119  Atom selection_string_atom_;
120  Atom targets_atom_;
121  Atom timestamp_atom_;
122  Atom utf8_string_atom_;
123
124  // The set of X selections owned by |clipboard_window_| (can be Primary or
125  // Clipboard or both).
126  std::set<Atom> selections_owned_;
127
128  // Clipboard content to return to other applications when |clipboard_window_|
129  // owns a selection.
130  std::string data_;
131
132  // Stores the property to use for large transfers, or None if a large
133  // transfer is not currently in-progress.
134  Atom large_selection_property_;
135
136  // Remembers the start time of selection processing, and is set to null when
137  // processing is complete. This is used to decide whether to begin processing
138  // a new selection or continue with the current selection.
139  base::TimeTicks get_selections_time_;
140
141  // |callback| argument supplied to Init().
142  ClipboardChangedCallback callback_;
143
144  DISALLOW_COPY_AND_ASSIGN(XServerClipboard);
145};
146
147}  // namespace remoting
148
149#endif  // REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
150