summaryrefslogtreecommitdiffstats
path: root/remoting/host/linux/x_server_clipboard.h
blob: c8d56918fc3a780675315a7e6101195853260af6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2012 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.

// Don't include this file from any .h files because it pulls in some X headers.

#ifndef REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
#define REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_

#include <X11/Xatom.h>
#include <X11/Xlib.h>

#include <set>
#include <string>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/time/time.h"

namespace remoting {

// A class to allow manipulation of the X clipboard, using only X API calls.
// This class is not thread-safe, so all its methods must be called on the
// application's main event-processing thread.
class XServerClipboard {
 public:
  // Called when new clipboard data has been received from the owner of the X
  // selection (primary or clipboard).
  // |mime_type| is the MIME type associated with the data. This will be one of
  // the types listed in remoting/base/constants.h.
  // |data| is the clipboard data from the associated X event, encoded with the
  // specified MIME-type.
  typedef base::Callback<void(const std::string& mime_type,
                              const std::string& data)>
      ClipboardChangedCallback;

  XServerClipboard();
  ~XServerClipboard();

  // Start monitoring |display|'s selections, and invoke |callback| whenever
  // their content changes. The caller must ensure |display| is still valid
  // whenever any other methods are called on this object.
  void Init(Display* display, const ClipboardChangedCallback& callback);

  // Copy data to the X Clipboard.  This acquires ownership of the
  // PRIMARY and CLIPBOARD selections.
  void SetClipboard(const std::string& mime_type, const std::string& data);

  // Process |event| if it is an X selection notification. The caller should
  // invoke this for every event it receives from |display|.
  void ProcessXEvent(XEvent* event);

 private:
  // Handlers called by ProcessXEvent() for each event type.
  void OnSetSelectionOwnerNotify(Atom selection, Time timestamp);
  void OnPropertyNotify(XEvent* event);
  void OnSelectionNotify(XEvent* event);
  void OnSelectionRequest(XEvent* event);
  void OnSelectionClear(XEvent* event);

  // Used by OnSelectionRequest() to respond to requests for details of our
  // clipboard content. This is done by changing the property |property| of the
  // |requestor| window (these values come from the XSelectionRequestEvent).
  // |target| must be a string type (STRING or UTF8_STRING).
  void SendTargetsResponse(Window requestor, Atom property);
  void SendTimestampResponse(Window requestor, Atom property);
  void SendStringResponse(Window requestor, Atom property, Atom target);

  // Called by OnSelectionNotify() when the selection owner has replied to a
  // request for information about a selection.
  // |event| is the raw X event from the notification.
  // |type|, |format| etc are the results from XGetWindowProperty(), or 0 if
  // there is no associated data.
  void HandleSelectionNotify(XSelectionEvent* event,
                             Atom type,
                             int format,
                             int item_count,
                             void* data);

  // These methods return true if selection processing is complete, false
  // otherwise. They are called from HandleSelectionNotify(), and take the same
  // arguments.
  bool HandleSelectionTargetsEvent(XSelectionEvent* event,
                                   int format,
                                   int item_count,
                                   void* data);
  bool HandleSelectionStringEvent(XSelectionEvent* event,
                                  int format,
                                  int item_count,
                                  void* data);

  // Notify the registered callback of new clipboard text.
  void NotifyClipboardText(const std::string& text);

  // These methods trigger the X server or selection owner to send back an
  // event containing the requested information.
  void RequestSelectionTargets(Atom selection);
  void RequestSelectionString(Atom selection, Atom target);

  // Assert ownership of the specified |selection|.
  void AssertSelectionOwnership(Atom selection);
  bool IsSelectionOwner(Atom selection);

  // Stores the Display* supplied to Init().
  Display* display_;

  // Window through which clipboard events are received, or BadValue if the
  // window could not be created.
  Window clipboard_window_;

  // The event base returned by XFixesQueryExtension(). If XFixes is
  // unavailable, the clipboard window will not be created, and no
  // event-processing will take place.
  int xfixes_event_base_;

  // Cached atoms for various strings, initialized during Init().
  Atom clipboard_atom_;
  Atom large_selection_atom_;
  Atom selection_string_atom_;
  Atom targets_atom_;
  Atom timestamp_atom_;
  Atom utf8_string_atom_;

  // The set of X selections owned by |clipboard_window_| (can be Primary or
  // Clipboard or both).
  std::set<Atom> selections_owned_;

  // Clipboard content to return to other applications when |clipboard_window_|
  // owns a selection.
  std::string data_;

  // Stores the property to use for large transfers, or None if a large
  // transfer is not currently in-progress.
  Atom large_selection_property_;

  // Remembers the start time of selection processing, and is set to null when
  // processing is complete. This is used to decide whether to begin processing
  // a new selection or continue with the current selection.
  base::TimeTicks get_selections_time_;

  // |callback| argument supplied to Init().
  ClipboardChangedCallback callback_;

  DISALLOW_COPY_AND_ASSIGN(XServerClipboard);
};

}  // namespace remoting

#endif  // REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_