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