Home | History | Annotate | Download | only in host
      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 
     56 ClipboardX11::ClipboardX11()
     57     : display_(NULL) {
     58 }
     59 
     60 ClipboardX11::~ClipboardX11() {
     61   Stop();
     62 }
     63 
     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 
     87 void ClipboardX11::InjectClipboardEvent(
     88     const protocol::ClipboardEvent& event) {
     89   x_server_clipboard_.SetClipboard(event.mime_type(), event.data());
     90 }
     91 
     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 
    102 void ClipboardX11::OnFileCanReadWithoutBlocking(int fd) {
    103   PumpXEvents();
    104 }
    105 
    106 void ClipboardX11::OnFileCanWriteWithoutBlocking(int fd) {
    107 }
    108 
    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 
    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 
    130 scoped_ptr<Clipboard> Clipboard::Create() {
    131   return scoped_ptr<Clipboard>(new ClipboardX11());
    132 }
    133 
    134 }  // namespace remoting
    135