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 16namespace remoting { 17 18// This code is expected to be called on the desktop thread only. 19class 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 56ClipboardX11::ClipboardX11() 57 : display_(NULL) { 58} 59 60ClipboardX11::~ClipboardX11() { 61 Stop(); 62} 63 64void 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 87void ClipboardX11::InjectClipboardEvent( 88 const protocol::ClipboardEvent& event) { 89 x_server_clipboard_.SetClipboard(event.mime_type(), event.data()); 90} 91 92void ClipboardX11::Stop() { 93 client_clipboard_.reset(); 94 x_connection_watcher_.StopWatchingFileDescriptor(); 95 96 if (display_) { 97 XCloseDisplay(display_); 98 display_ = NULL; 99 } 100} 101 102void ClipboardX11::OnFileCanReadWithoutBlocking(int fd) { 103 PumpXEvents(); 104} 105 106void ClipboardX11::OnFileCanWriteWithoutBlocking(int fd) { 107} 108 109void 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 120void 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 130scoped_ptr<Clipboard> Clipboard::Create() { 131 return scoped_ptr<Clipboard>(new ClipboardX11()); 132} 133 134} // namespace remoting 135