| Index: remoting/host/clipboard_linux.cc
|
| diff --git a/remoting/host/clipboard_linux.cc b/remoting/host/clipboard_linux.cc
|
| index 6a1729167fccf9aeea4617c719d28d037e3290a2..d028632f4c1245d70980c39be6f5df7a67559df5 100644
|
| --- a/remoting/host/clipboard_linux.cc
|
| +++ b/remoting/host/clipboard_linux.cc
|
| @@ -4,13 +4,23 @@
|
|
|
| #include "remoting/host/clipboard.h"
|
|
|
| +#include <X11/Xlib.h>
|
| +
|
| +#include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/message_pump_libevent.h"
|
| +#include "base/threading/thread.h"
|
| +#include "remoting/host/x_server_clipboard.h"
|
| +#include "remoting/proto/event.pb.h"
|
| +#include "remoting/protocol/clipboard_stub.h"
|
|
|
| namespace remoting {
|
|
|
| -class ClipboardLinux : public Clipboard {
|
| +class ClipboardLinux : public Clipboard, base::MessagePumpLibevent::Watcher {
|
| public:
|
| ClipboardLinux();
|
| + ~ClipboardLinux();
|
|
|
| // Must be called on the UI thread.
|
| virtual void Start(
|
| @@ -20,21 +30,121 @@ class ClipboardLinux : public Clipboard {
|
| virtual void Stop() OVERRIDE;
|
|
|
| private:
|
| + void OnClipboardChanged(const std::string& mime_type,
|
| + const std::string& data);
|
| + void PumpEvents();
|
| +
|
| + // base::MessagePumpLibevent::Watcher interface
|
| + virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
|
| + virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
|
| +
|
| + scoped_ptr<protocol::ClipboardStub> client_clipboard_;
|
| +
|
| + XServerClipboard x_server_clipboard_;
|
| + Display* display_;
|
| + base::Thread x11_thread_;
|
| +
|
| + base::MessagePumpLibevent::FileDescriptorWatcher x_connection_watcher_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(ClipboardLinux);
|
| };
|
|
|
| +ClipboardLinux::ClipboardLinux()
|
| + : display_(NULL),
|
| + x11_thread_("Clipboard X11 thread") {
|
| + x11_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
|
| +}
|
| +
|
| +ClipboardLinux::~ClipboardLinux() {
|
| + Stop();
|
| + x11_thread_.Stop();
|
| +}
|
| +
|
| void ClipboardLinux::Start(
|
| scoped_ptr<protocol::ClipboardStub> client_clipboard) {
|
| - NOTIMPLEMENTED();
|
| + if (!x11_thread_.message_loop_proxy()->BelongsToCurrentThread()) {
|
| + // base::Unretained is safe, since the clipboard thread is owned by this
|
| + // object.
|
| + x11_thread_.message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ClipboardLinux::Start, base::Unretained(this),
|
| + base::Passed(client_clipboard.Pass())));
|
| + return;
|
| + }
|
| +
|
| + display_ = XOpenDisplay(NULL);
|
| + if (!display_) {
|
| + LOG(ERROR) << "Couldn't open X display";
|
| + return;
|
| + }
|
| + client_clipboard_.swap(client_clipboard);
|
| +
|
| + // base::Unretained is safe, since the clipboard thread is owned by this
|
| + // object, and this dtor resets |callback_|, so that no more clipboard
|
| + // changes are processed while stopping the thread.
|
| + x_server_clipboard_.Init(display_,
|
| + base::Bind(&ClipboardLinux::OnClipboardChanged,
|
| + base::Unretained(this)));
|
| +
|
| + MessageLoopForIO::current()->WatchFileDescriptor(
|
| + ConnectionNumber(display_), true, MessageLoopForIO::WATCH_READ,
|
| + &x_connection_watcher_, this);
|
| }
|
|
|
| void ClipboardLinux::InjectClipboardEvent(
|
| const protocol::ClipboardEvent& event) {
|
| - NOTIMPLEMENTED();
|
| + if (!x11_thread_.message_loop_proxy()->BelongsToCurrentThread()) {
|
| + x11_thread_.message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ClipboardLinux::InjectClipboardEvent,
|
| + base::Unretained(this),
|
| + event));
|
| + return;
|
| + }
|
| +
|
| + x_server_clipboard_.SetClipboard(event.mime_type(), event.data());
|
| }
|
|
|
| void ClipboardLinux::Stop() {
|
| - NOTIMPLEMENTED();
|
| + if (!x11_thread_.message_loop_proxy()->BelongsToCurrentThread()) {
|
| + x11_thread_.message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ClipboardLinux::Stop, base::Unretained(this)));
|
| + return;
|
| + }
|
| +
|
| + client_clipboard_.reset();
|
| + x_connection_watcher_.StopWatchingFileDescriptor();
|
| +
|
| + if (display_) {
|
| + XCloseDisplay(display_);
|
| + display_ = NULL;
|
| + }
|
| +}
|
| +
|
| +void ClipboardLinux::OnClipboardChanged(const std::string& mime_type,
|
| + const std::string& data) {
|
| + protocol::ClipboardEvent event;
|
| + event.set_mime_type(mime_type);
|
| + event.set_data(data);
|
| +
|
| + if (client_clipboard_.get()) {
|
| + client_clipboard_->InjectClipboardEvent(event);
|
| + }
|
| +}
|
| +
|
| +void ClipboardLinux::PumpEvents() {
|
| + DCHECK(display_);
|
| +
|
| + while (XPending(display_)) {
|
| + XEvent event;
|
| + XNextEvent(display_, &event);
|
| + x_server_clipboard_.ProcessXEvent(&event);
|
| + }
|
| +}
|
| +
|
| +void ClipboardLinux::OnFileCanReadWithoutBlocking(int fd) {
|
| + PumpEvents();
|
| }
|
|
|
| scoped_ptr<Clipboard> Clipboard::Create() {
|
|
|