| Index: remoting/client/x11_client.cc
|
| diff --git a/remoting/client/x11_client.cc b/remoting/client/x11_client.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6b8e4e2d3ee3a6ba54fe4f3d0cd389d33d53c981
|
| --- /dev/null
|
| +++ b/remoting/client/x11_client.cc
|
| @@ -0,0 +1,262 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +//
|
| +// This file implements a X11 chromoting client.
|
| +
|
| +#include <iostream>
|
| +
|
| +#include "base/at_exit.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/stl_util-inl.h"
|
| +#include "remoting/client/host_connection.h"
|
| +#include "remoting/client/client_util.h"
|
| +
|
| +// Include Xlib at the end because it clashes with ClientMessage defined in
|
| +// the protocol buffer.
|
| +// x11_view.h also includes Xlib.h so put it behind all other headers but
|
| +// before Xlib.h
|
| +#include "remoting/client/x11_view.h"
|
| +#include <X11/Xlib.h>
|
| +
|
| +namespace remoting {
|
| +
|
| +class X11Client : public base::RefCountedThreadSafe<X11Client>,
|
| + public HostConnection::EventHandler {
|
| + public:
|
| + X11Client(std::string host_jid, std::string username, std::string auth_token)
|
| + : display_(NULL),
|
| + window_(0),
|
| + width_(0),
|
| + height_(0),
|
| + host_jid_(host_jid),
|
| + username_(username),
|
| + auth_token_(auth_token) {
|
| + }
|
| +
|
| + virtual ~X11Client() {
|
| + DCHECK(!display_);
|
| + DCHECK(!window_);
|
| + }
|
| +
|
| + // Starts the remoting client and the message loop. Returns only after
|
| + // the message loop has terminated.
|
| + void Run() {
|
| + message_loop_.PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoInitX11));
|
| + message_loop_.PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoInitConnection));
|
| + message_loop_.Run();
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////////////////////
|
| + // HostConnection::EventHandler implementations.
|
| + virtual void HandleMessages(HostConnection* conn,
|
| + remoting::HostMessageList* messages) {
|
| + for (size_t i = 0; i < messages->size(); ++i) {
|
| + HostMessage* msg = (*messages)[i];
|
| + if (msg->has_init_client()) {
|
| + message_loop_.PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &X11Client::DoInitClient, msg));
|
| + } else if (msg->has_begin_update_stream()) {
|
| + message_loop_.PostTask(
|
| + FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoBeginUpdate, msg));
|
| + } else if (msg->has_update_stream_packet()) {
|
| + message_loop_.PostTask(
|
| + FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoHandleUpdate, msg));
|
| + } else if (msg->has_end_update_stream()) {
|
| + message_loop_.PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &X11Client::DoEndUpdate, msg));
|
| + } else {
|
| + NOTREACHED() << "Unknown message received";
|
| + }
|
| + }
|
| + // Assume we have processed all the messages.
|
| + messages->clear();
|
| + }
|
| +
|
| + virtual void OnConnectionOpened(HostConnection* conn) {
|
| + std::cout << "Connection establised." << std::endl;
|
| + }
|
| +
|
| + virtual void OnConnectionClosed(HostConnection* conn) {
|
| + std::cout << "Connection closed." << std::endl;
|
| + Exit();
|
| + }
|
| +
|
| + virtual void OnConnectionFailed(HostConnection* conn) {
|
| + std::cout << "Conection failed." << std::endl;
|
| + Exit();
|
| + }
|
| +
|
| + private:
|
| + void DoInitX11() {
|
| + display_ = XOpenDisplay(NULL);
|
| + if (!display_) {
|
| + std::cout << "Error - cannot open display" << std::endl;
|
| + Exit();
|
| + }
|
| +
|
| + // Get properties of the screen.
|
| + int screen = DefaultScreen(display_);
|
| + int root_window = RootWindow(display_, screen);
|
| +
|
| + // Creates the window.
|
| + window_ = XCreateSimpleWindow(display_, root_window, 1, 1, 640, 480, 0,
|
| + BlackPixel(display_, screen),
|
| + BlackPixel(display_, screen));
|
| + DCHECK(window_);
|
| + XStoreName(display_, window_, "X11 Remoting");
|
| +
|
| + // Specifies what kind of messages we want to receive.
|
| + XSelectInput(display_, window_, ExposureMask | ButtonPressMask);
|
| + XMapWindow(display_, window_);
|
| + }
|
| +
|
| + void DoInitConnection() {
|
| + // If the initialization of X11 has failed then return directly.
|
| + if (!display_)
|
| + return;
|
| +
|
| + // Creates a HostConnection object and connection to the host.
|
| + LOG(INFO) << "Connecting...";
|
| + connection_.reset(new HostConnection(new ProtocolDecoder(), this));
|
| + connection_->Connect(username_, auth_token_, host_jid_);
|
| + }
|
| +
|
| + void DoDestroyX11() {
|
| + if (display_ && window_) {
|
| + // Shutdown the window system.
|
| + XDestroyWindow(display_, window_);
|
| + XCloseDisplay(display_);
|
| + display_ = NULL;
|
| + window_ = 0;
|
| + }
|
| + }
|
| +
|
| + void DoDisconnect() {
|
| + if (connection_.get())
|
| + connection_->Disconnect();
|
| + }
|
| +
|
| + void Exit() {
|
| + // Disconnect the jingle channel and client.
|
| + message_loop_.PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoDisconnect));
|
| +
|
| + // Post a task to shutdown X11.
|
| + message_loop_.PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoDestroyX11));
|
| +
|
| + // Quit the current message loop.
|
| + message_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask());
|
| + }
|
| +
|
| + // This method is executed on the main loop.
|
| + void DoInitClient(HostMessage* msg) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + DCHECK(msg->has_init_client());
|
| + scoped_ptr<HostMessage> deleter(msg);
|
| +
|
| + // Saves the dimension and resize the window.
|
| + width_ = msg->init_client().width();
|
| + height_ = msg->init_client().height();
|
| + LOG(INFO) << "Init client receievd: " << width_ << "x" << height_;
|
| + XResizeWindow(display_, window_, width_, height_);
|
| +
|
| + // Now construct the X11View that renders the remote desktop.
|
| + view_ = new X11View(display_, window_, width_, height_);
|
| +
|
| + // Schedule the event handler to process the event queue of X11.
|
| + ScheduleX11EventHandler();
|
| + }
|
| +
|
| + // The following methods are executed on the same thread as libjingle.
|
| + void DoBeginUpdate(HostMessage* msg) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + DCHECK(msg->has_begin_update_stream());
|
| +
|
| + view_->HandleBeginUpdateStream(msg);
|
| + }
|
| +
|
| + void DoHandleUpdate(HostMessage* msg) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + DCHECK(msg->has_update_stream_packet());
|
| +
|
| + view_->HandleUpdateStreamPacket(msg);
|
| + }
|
| +
|
| + void DoEndUpdate(HostMessage* msg) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + DCHECK(msg->has_end_update_stream());
|
| +
|
| + view_->HandleEndUpdateStream(msg);
|
| + }
|
| +
|
| + void DoProcessX11Events() {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + if (XPending(display_)) {
|
| + XEvent e;
|
| + XNextEvent(display_, &e);
|
| + if (e.type == Expose) {
|
| + // Tell the ChromotingView to paint again.
|
| + view_->Paint();
|
| + } else if (e.type == ButtonPress) {
|
| + // TODO(hclam): Implement.
|
| + NOTIMPLEMENTED();
|
| + } else {
|
| + // TODO(hclam): Implement.
|
| + NOTIMPLEMENTED();
|
| + }
|
| + }
|
| +
|
| + // Schedule the next event handler.
|
| + ScheduleX11EventHandler();
|
| + }
|
| +
|
| + void ScheduleX11EventHandler() {
|
| + // Schedule a delayed task to process X11 events in 10ms.
|
| + static const int kProcessEventsInterval = 10;
|
| + message_loop_.PostDelayedTask(
|
| + FROM_HERE,
|
| + NewRunnableMethod(this, &X11Client::DoProcessX11Events),
|
| + kProcessEventsInterval);
|
| + }
|
| +
|
| + // Members used for display.
|
| + Display* display_;
|
| + Window window_;
|
| +
|
| + // Dimension of the window. They are initialized when InitClient message is
|
| + // received.
|
| + int width_;
|
| + int height_;
|
| +
|
| + std::string host_jid_;
|
| + std::string username_;
|
| + std::string auth_token_;
|
| + scoped_ptr<HostConnection> connection_;
|
| + scoped_refptr<ChromotingView> view_;
|
| +
|
| + MessageLoop message_loop_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(X11Client);
|
| +};
|
| +
|
| +} // namespace remoting
|
| +
|
| +int main() {
|
| + base::AtExitManager at_exit;
|
| + std::string host_jid, username, auth_token;
|
| +
|
| + if (!remoting::GetLoginInfo(host_jid, username, auth_token)) {
|
| + std::cout << "Cannot obtain login info" << std::endl;
|
| + return 1;
|
| + }
|
| +
|
| + scoped_refptr<remoting::X11Client> client =
|
| + new remoting::X11Client(host_jid, username, auth_token);
|
| + client->Run();
|
| +}
|
|
|