15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Don't include this file from any .h files because it pulls in some X headers.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xatom.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xlib.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback_forward.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class to allow manipulation of the X clipboard, using only X API calls.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is not thread-safe, so all its methods must be called on the
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// application's main event-processing thread.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XServerClipboard {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Called when new clipboard data has been received from the owner of the X
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // selection (primary or clipboard).
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |mime_type| is the MIME type associated with the data. This will be one of
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the types listed in remoting/base/constants.h.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |data| is the clipboard data from the associated X event, encoded with the
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // specified MIME-type.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::Callback<void(const std::string& mime_type,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& data)>
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ClipboardChangedCallback;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XServerClipboard();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XServerClipboard();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start monitoring |display|'s selections, and invoke |callback| whenever
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // their content changes. The caller must ensure |display| is still valid
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whenever any other methods are called on this object.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(Display* display, const ClipboardChangedCallback& callback);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy data to the X Clipboard.  This acquires ownership of the
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PRIMARY and CLIPBOARD selections.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetClipboard(const std::string& mime_type, const std::string& data);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Process |event| if it is an X selection notification. The caller should
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invoke this for every event it receives from |display|.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ProcessXEvent(XEvent* event);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Handlers called by ProcessXEvent() for each event type.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnSetSelectionOwnerNotify(Atom selection, Time timestamp);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnPropertyNotify(XEvent* event);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnSelectionNotify(XEvent* event);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnSelectionRequest(XEvent* event);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnSelectionClear(XEvent* event);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Used by OnSelectionRequest() to respond to requests for details of our
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // clipboard content. This is done by changing the property |property| of the
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |requestor| window (these values come from the XSelectionRequestEvent).
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |target| must be a string type (STRING or UTF8_STRING).
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SendTargetsResponse(Window requestor, Atom property);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SendTimestampResponse(Window requestor, Atom property);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SendStringResponse(Window requestor, Atom property, Atom target);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Called by OnSelectionNotify() when the selection owner has replied to a
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // request for information about a selection.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |event| is the raw X event from the notification.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |type|, |format| etc are the results from XGetWindowProperty(), or 0 if
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // there is no associated data.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void HandleSelectionNotify(XSelectionEvent* event,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             Atom type,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int format,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int item_count,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             void* data);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These methods return true if selection processing is complete, false
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // otherwise. They are called from HandleSelectionNotify(), and take the same
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // arguments.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HandleSelectionTargetsEvent(XSelectionEvent* event,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int format,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int item_count,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   void* data);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HandleSelectionStringEvent(XSelectionEvent* event,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int format,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int item_count,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  void* data);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify the registered callback of new clipboard text.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyClipboardText(const std::string& text);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These methods trigger the X server or selection owner to send back an
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // event containing the requested information.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RequestSelectionTargets(Atom selection);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RequestSelectionString(Atom selection, Atom target);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Assert ownership of the specified |selection|.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AssertSelectionOwnership(Atom selection);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsSelectionOwner(Atom selection);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stores the Display* supplied to Init().
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Display* display_;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Window through which clipboard events are received, or BadValue if the
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // window could not be created.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window clipboard_window_;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The event base returned by XFixesQueryExtension(). If XFixes is
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // unavailable, the clipboard window will not be created, and no
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // event-processing will take place.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int xfixes_event_base_;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Cached atoms for various strings, initialized during Init().
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom clipboard_atom_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom large_selection_atom_;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom selection_string_atom_;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom targets_atom_;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom timestamp_atom_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom utf8_string_atom_;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The set of X selections owned by |clipboard_window_| (can be Primary or
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clipboard or both).
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<Atom> selections_owned_;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clipboard content to return to other applications when |clipboard_window_|
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // owns a selection.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data_;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stores the property to use for large transfers, or None if a large
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // transfer is not currently in-progress.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom large_selection_property_;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remembers the start time of selection processing, and is set to null when
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // processing is complete. This is used to decide whether to begin processing
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // a new selection or continue with the current selection.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks get_selections_time_;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |callback| argument supplied to Init().
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClipboardChangedCallback callback_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XServerClipboard);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // REMOTING_HOST_LINUX_X_SERVER_CLIPBOARD_H_
150