• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "remoting/host/clipboard.h"
6 
7 #include <X11/Xlib.h>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "remoting/host/linux/x_server_clipboard.h"
13 #include "remoting/proto/event.pb.h"
14 #include "remoting/protocol/clipboard_stub.h"
15 
16 namespace remoting {
17 
18 // This code is expected to be called on the desktop thread only.
19 class ClipboardX11 : public Clipboard,
20                      public base::MessageLoopForIO::Watcher {
21  public:
22   ClipboardX11();
23   virtual ~ClipboardX11();
24 
25   // Clipboard interface.
26   virtual void Start(
27       scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
28   virtual void InjectClipboardEvent(
29       const protocol::ClipboardEvent& event) OVERRIDE;
30   virtual void Stop() OVERRIDE;
31 
32   // MessageLoopForIO::Watcher interface.
33   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
34   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
35 
36  private:
37   void OnClipboardChanged(const std::string& mime_type,
38                           const std::string& data);
39   void PumpXEvents();
40 
41   scoped_ptr<protocol::ClipboardStub> client_clipboard_;
42 
43   // Underlying X11 clipboard implementation.
44   XServerClipboard x_server_clipboard_;
45 
46   // Connection to the X server, used by |x_server_clipboard_|. This is created
47   // and owned by this class.
48   Display* display_;
49 
50   // Watcher used to handle X11 events from |display_|.
51   base::MessageLoopForIO::FileDescriptorWatcher x_connection_watcher_;
52 
53   DISALLOW_COPY_AND_ASSIGN(ClipboardX11);
54 };
55 
ClipboardX11()56 ClipboardX11::ClipboardX11()
57     : display_(NULL) {
58 }
59 
~ClipboardX11()60 ClipboardX11::~ClipboardX11() {
61   Stop();
62 }
63 
Start(scoped_ptr<protocol::ClipboardStub> client_clipboard)64 void ClipboardX11::Start(
65     scoped_ptr<protocol::ClipboardStub> client_clipboard) {
66   // TODO(lambroslambrou): Share the X connection with InputInjector.
67   display_ = XOpenDisplay(NULL);
68   if (!display_) {
69     LOG(ERROR) << "Couldn't open X display";
70     return;
71   }
72   client_clipboard_.swap(client_clipboard);
73 
74   x_server_clipboard_.Init(display_,
75                            base::Bind(&ClipboardX11::OnClipboardChanged,
76                                       base::Unretained(this)));
77 
78   base::MessageLoopForIO::current()->WatchFileDescriptor(
79       ConnectionNumber(display_),
80       true,
81       base::MessageLoopForIO::WATCH_READ,
82       &x_connection_watcher_,
83       this);
84   PumpXEvents();
85 }
86 
InjectClipboardEvent(const protocol::ClipboardEvent & event)87 void ClipboardX11::InjectClipboardEvent(
88     const protocol::ClipboardEvent& event) {
89   x_server_clipboard_.SetClipboard(event.mime_type(), event.data());
90 }
91 
Stop()92 void ClipboardX11::Stop() {
93   client_clipboard_.reset();
94   x_connection_watcher_.StopWatchingFileDescriptor();
95 
96   if (display_) {
97     XCloseDisplay(display_);
98     display_ = NULL;
99   }
100 }
101 
OnFileCanReadWithoutBlocking(int fd)102 void ClipboardX11::OnFileCanReadWithoutBlocking(int fd) {
103   PumpXEvents();
104 }
105 
OnFileCanWriteWithoutBlocking(int fd)106 void ClipboardX11::OnFileCanWriteWithoutBlocking(int fd) {
107 }
108 
OnClipboardChanged(const std::string & mime_type,const std::string & data)109 void ClipboardX11::OnClipboardChanged(const std::string& mime_type,
110                                       const std::string& data) {
111   protocol::ClipboardEvent event;
112   event.set_mime_type(mime_type);
113   event.set_data(data);
114 
115   if (client_clipboard_.get()) {
116     client_clipboard_->InjectClipboardEvent(event);
117   }
118 }
119 
PumpXEvents()120 void ClipboardX11::PumpXEvents() {
121   DCHECK(display_);
122 
123   while (XPending(display_)) {
124     XEvent event;
125     XNextEvent(display_, &event);
126     x_server_clipboard_.ProcessXEvent(&event);
127   }
128 }
129 
Create()130 scoped_ptr<Clipboard> Clipboard::Create() {
131   return scoped_ptr<Clipboard>(new ClipboardX11());
132 }
133 
134 }  // namespace remoting
135