summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorgarykac@google.com <garykac@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-20 00:34:57 +0000
committergarykac@google.com <garykac@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-20 00:34:57 +0000
commit4d37c874d917cc370e188cfdef05bb629388421a (patch)
tree08f68e3ef47406ae69209f489832fa8f1c76448e /remoting
parent0af395eb3fa7d33473b4239a7b637fc6a7ce0e98 (diff)
downloadchromium_src-4d37c874d917cc370e188cfdef05bb629388421a.zip
chromium_src-4d37c874d917cc370e188cfdef05bb629388421a.tar.gz
chromium_src-4d37c874d917cc370e188cfdef05bb629388421a.tar.bz2
Refactor the client code for the X11 version.
Make ChromotingViews responsible for initializing themselves. Move all x11-related code into X11View. Create InputCapturer class manage client input capture. BUG=none TEST=ran Win host + X11 client Review URL: http://codereview.chromium.org/2861047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52973 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/client/chromoting_client.cc150
-rw-r--r--remoting/client/chromoting_client.h42
-rw-r--r--remoting/client/chromoting_view.h15
-rw-r--r--remoting/client/client_config.h36
-rw-r--r--remoting/client/client_context.cc52
-rw-r--r--remoting/client/client_context.h48
-rw-r--r--remoting/client/client_util.cc93
-rw-r--r--remoting/client/client_util.h12
-rw-r--r--remoting/client/client_util_unittest.cc36
-rw-r--r--remoting/client/host_connection.h6
-rw-r--r--remoting/client/input_handler.h28
-rw-r--r--remoting/client/jingle_host_connection.cc25
-rw-r--r--remoting/client/jingle_host_connection.h14
-rw-r--r--remoting/client/plugin/chromoting_plugin.cc87
-rw-r--r--remoting/client/plugin/chromoting_plugin.h14
-rw-r--r--remoting/client/plugin/chromoting_plugin_unittest.cc13
-rw-r--r--remoting/client/plugin/pepper_input_handler.cc19
-rw-r--r--remoting/client/plugin/pepper_input_handler.h27
-rw-r--r--remoting/client/plugin/pepper_view.cc11
-rw-r--r--remoting/client/plugin/pepper_view.h4
-rw-r--r--remoting/client/simple_client.cc148
-rw-r--r--remoting/client/x11_client.cc259
-rw-r--r--remoting/client/x11_input_handler.cc62
-rw-r--r--remoting/client/x11_input_handler.h38
-rw-r--r--remoting/client/x11_view.cc67
-rw-r--r--remoting/client/x11_view.h7
-rw-r--r--remoting/host/chromoting_host_context.h12
-rw-r--r--remoting/remoting.gyp23
28 files changed, 710 insertions, 638 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index 39f18b4..7b77ee7 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -6,7 +6,10 @@
#include "base/message_loop.h"
#include "remoting/client/chromoting_view.h"
+#include "remoting/client/client_config.h"
+#include "remoting/client/client_context.h"
#include "remoting/client/host_connection.h"
+#include "remoting/client/input_handler.h"
static const uint32 kCreatedColor = 0xffccccff;
static const uint32 kDisconnectedColor = 0xff00ccff;
@@ -14,53 +17,106 @@ static const uint32 kFailedColor = 0xffcc00ff;
namespace remoting {
-ChromotingClient::ChromotingClient(MessageLoop* message_loop,
+ChromotingClient::ChromotingClient(ClientConfig* config,
+ ClientContext* context,
HostConnection* connection,
- ChromotingView* view)
- : message_loop_(message_loop),
- state_(CREATED),
- host_connection_(connection),
- view_(view) {
+ ChromotingView* view,
+ InputHandler* input_handler,
+ CancelableTask* client_done)
+ : config_(config),
+ context_(context),
+ connection_(connection),
+ view_(view),
+ input_handler_(input_handler),
+ client_done_(client_done),
+ state_(CREATED) {
}
ChromotingClient::~ChromotingClient() {
}
+void ChromotingClient::Start() {
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::Start));
+ return;
+ }
+
+ connection_->Connect(config_, this);
+
+ if (!view_->Initialize()) {
+ ClientDone();
+ }
+}
+
+void ChromotingClient::Stop() {
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::Stop));
+ return;
+ }
+
+ connection_->Disconnect();
+
+ view_->TearDown();
+
+ // Quit the current message loop.
+ message_loop()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+}
+
+void ChromotingClient::ClientDone() {
+ if (client_done_ != NULL) {
+ message_loop()->PostTask(FROM_HERE, client_done_);
+ }
+}
+
void ChromotingClient::Repaint() {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoRepaint));
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::Repaint));
+ return;
+ }
+
+ view_->Paint();
}
void ChromotingClient::SetViewport(int x, int y, int width, int height) {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoSetViewport,
- x, y, width, height));
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::SetViewport,
+ x, y, width, height));
+ return;
+ }
+
+ view_->SetViewport(x, y, width, height);
}
void ChromotingClient::HandleMessages(HostConnection* conn,
HostMessageList* messages) {
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::HandleMessages,
+ conn, messages));
+ return;
+ }
+
for (size_t i = 0; i < messages->size(); ++i) {
HostMessage* msg = (*messages)[i];
// TODO(ajwong): Consider creating a macro similar to the IPC message
// mappings. Also reconsider the lifetime of the message object.
if (msg->has_init_client()) {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoInitClient, msg));
+ InitClient(msg);
} else if (msg->has_begin_update_stream()) {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoBeginUpdate, msg));
+ BeginUpdate(msg);
} else if (msg->has_update_stream_packet()) {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoHandleUpdate, msg));
+ HandleUpdate(msg);
} else if (msg->has_end_update_stream()) {
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoEndUpdate, msg));
+ EndUpdate(msg);
} else {
NOTREACHED() << "Unknown message received";
}
@@ -85,19 +141,18 @@ void ChromotingClient::OnConnectionFailed(HostConnection* conn) {
}
MessageLoop* ChromotingClient::message_loop() {
- return message_loop_;
+ return context_->jingle_thread()->message_loop();
}
void ChromotingClient::SetState(State s) {
// TODO(ajwong): We actually may want state to be a shared variable. Think
// through later.
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &ChromotingClient::DoSetState, s));
-}
-
-void ChromotingClient::DoSetState(State s) {
- DCHECK_EQ(message_loop(), MessageLoop::current());
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::SetState, s));
+ return;
+ }
state_ = s;
switch (state_) {
@@ -118,49 +173,40 @@ void ChromotingClient::DoSetState(State s) {
break;
}
- DoRepaint();
+ Repaint();
}
-void ChromotingClient::DoRepaint() {
- DCHECK_EQ(message_loop(), MessageLoop::current());
-
- view_->Paint();
-}
-
-void ChromotingClient::DoSetViewport(int x, int y, int width, int height) {
- DCHECK_EQ(message_loop(), MessageLoop::current());
-
- view_->SetViewport(x, y, width, height);
-}
-
-void ChromotingClient::DoInitClient(HostMessage* msg) {
+void ChromotingClient::InitClient(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.
+ // Resize the window.
int width = msg->init_client().width();
int height = msg->init_client().height();
LOG(INFO) << "Init client received geometry: " << width << "x" << height;
- view_->SetBackingStoreSize(width, height);
+ view_->SetHostScreenSize(width, height);
+
+ // Schedule the input handler to process the event queue.
+ input_handler_->Initialize();
}
-void ChromotingClient::DoBeginUpdate(HostMessage* msg) {
+void ChromotingClient::BeginUpdate(HostMessage* msg) {
DCHECK_EQ(message_loop(), MessageLoop::current());
DCHECK(msg->has_begin_update_stream());
view_->HandleBeginUpdateStream(msg);
}
-void ChromotingClient::DoHandleUpdate(HostMessage* msg) {
+void ChromotingClient::HandleUpdate(HostMessage* msg) {
DCHECK_EQ(message_loop(), MessageLoop::current());
DCHECK(msg->has_update_stream_packet());
view_->HandleUpdateStreamPacket(msg);
}
-void ChromotingClient::DoEndUpdate(HostMessage* msg) {
+void ChromotingClient::EndUpdate(HostMessage* msg) {
DCHECK_EQ(message_loop(), MessageLoop::current());
DCHECK(msg->has_end_update_stream());
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index 50cc0dc..331c805 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -15,14 +15,25 @@ class MessageLoop;
namespace remoting {
class ChromotingView;
+class ClientConfig;
+class ClientContext;
+class InputHandler;
class ChromotingClient : public HostConnection::HostEventCallback {
public:
- ChromotingClient(MessageLoop* message_loop,
+ // Objects passed in are not owned by this class.
+ ChromotingClient(ClientConfig* config,
+ ClientContext* context,
HostConnection* connection,
- ChromotingView* view);
+ ChromotingView* view,
+ InputHandler* input_handler,
+ CancelableTask* client_done);
virtual ~ChromotingClient();
+ void Start();
+ void Stop();
+ void ClientDone();
+
// Signals that the associated view may need updating.
virtual void Repaint();
@@ -53,25 +64,24 @@ class ChromotingClient : public HostConnection::HostEventCallback {
// Convenience method for modifying the state on this object's message loop.
void SetState(State s);
- // TODO(ajwong): Do all of these methods need to run on the client's thread?
- void DoSetState(State s);
- void DoRepaint();
- void DoSetViewport(int x, int y, int width, int height);
-
// Handles for chromotocol messages.
- void DoInitClient(HostMessage* msg);
- void DoBeginUpdate(HostMessage* msg);
- void DoHandleUpdate(HostMessage* msg);
- void DoEndUpdate(HostMessage* msg);
+ void InitClient(HostMessage* msg);
+ void BeginUpdate(HostMessage* msg);
+ void HandleUpdate(HostMessage* msg);
+ void EndUpdate(HostMessage* msg);
+
+ // The following are not owned by this class.
+ ClientConfig* config_;
+ ClientContext* context_;
+ HostConnection* connection_;
+ ChromotingView* view_;
+ InputHandler* input_handler_;
- MessageLoop* message_loop_;
+ // If non-NULL, this is called when the client is done.
+ CancelableTask* client_done_;
State state_;
- // Connection to views and hosts. Not owned.
- HostConnection* host_connection_;
- ChromotingView* view_;
-
DISALLOW_COPY_AND_ASSIGN(ChromotingClient);
};
diff --git a/remoting/client/chromoting_view.h b/remoting/client/chromoting_view.h
index 503a903..a50b407 100644
--- a/remoting/client/chromoting_view.h
+++ b/remoting/client/chromoting_view.h
@@ -18,6 +18,12 @@ class ChromotingView {
public:
virtual ~ChromotingView() {}
+ // Initialize the common structures for the view.
+ virtual bool Initialize() = 0;
+
+ // Free up resources allocated by this view.
+ virtual void TearDown() = 0;
+
// Tells the ChromotingView to paint the current image on the screen.
// TODO(hclam): Add rects as parameter if needed.
virtual void Paint() = 0;
@@ -34,12 +40,11 @@ class ChromotingView {
// extends past the end of the backing store, it is filled with black.
virtual void SetViewport(int x, int y, int width, int height) = 0;
- // Resize the underlying image that is displayed. This should match the size
- // of the output from the decoder.
+ // Resize the underlying image that contains the host screen buffer.
+ // This should match the size of the output from the decoder.
//
- // TODO(ajwong): We need a better name. Look at how Java represents this
- // stuff?
- virtual void SetBackingStoreSize(int width, int height) = 0;
+ // TODO(garykac): This handles only 1 screen. We need multi-screen support.
+ virtual void SetHostScreenSize(int width, int height) = 0;
// Handle the BeginUpdateStream message.
virtual void HandleBeginUpdateStream(HostMessage* msg) = 0;
diff --git a/remoting/client/client_config.h b/remoting/client/client_config.h
new file mode 100644
index 0000000..a02d9e8
--- /dev/null
+++ b/remoting/client/client_config.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_CLIENT_CONFIG_H_
+#define REMOTING_CLIENT_CLIENT_CONFIG_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace remoting {
+
+class ClientConfig {
+ public:
+ ClientConfig() { }
+
+ const std::string host_jid() { return host_jid_; }
+ const std::string username() { return username_; }
+ const std::string auth_token() { return auth_token_; }
+
+ void set_host_jid(std::string val) { host_jid_ = val; }
+ void set_username(std::string val) { username_ = val; }
+ void set_auth_token(std::string val) { auth_token_ = val; }
+
+ private:
+ std::string host_jid_;
+ std::string username_;
+ std::string auth_token_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientConfig);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_CLIENT_CONFIG_H_
diff --git a/remoting/client/client_context.cc b/remoting/client/client_context.cc
new file mode 100644
index 0000000..64b7cc1
--- /dev/null
+++ b/remoting/client/client_context.cc
@@ -0,0 +1,52 @@
+// 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.
+
+#include "remoting/client/client_context.h"
+
+#include <string>
+
+#include "base/thread.h"
+#include "remoting/jingle_glue/jingle_thread.h"
+
+namespace remoting {
+
+ClientContext::ClientContext()
+ : main_thread_("ChromotingClientMainThread"),
+ decode_thread_("ChromotingClientDecodeThread") {
+}
+
+ClientContext::~ClientContext() {
+}
+
+void ClientContext::Start() {
+ // Start all the threads.
+ main_thread_.Start();
+ decode_thread_.Start();
+ jingle_thread_.Start();
+}
+
+void ClientContext::Stop() {
+ // Stop all the threads.
+ jingle_thread_.Stop();
+ decode_thread_.Stop();
+ main_thread_.Stop();
+}
+
+JingleThread* ClientContext::jingle_thread() {
+ return &jingle_thread_;
+}
+
+MessageLoop* ClientContext::jingle_message_loop() {
+ return jingle_thread_.message_loop();
+}
+
+MessageLoop* ClientContext::main_message_loop() {
+ return main_thread_.message_loop();
+}
+
+MessageLoop* ClientContext::decode_message_loop() {
+ return decode_thread_.message_loop();
+}
+
+} // namespace remoting
diff --git a/remoting/client/client_context.h b/remoting/client/client_context.h
new file mode 100644
index 0000000..03273fb
--- /dev/null
+++ b/remoting/client/client_context.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_CLIENT_CONTEXT_H_
+#define REMOTING_CLIENT_CLIENT_CONTEXT_H_
+
+#include <string>
+
+#include "base/thread.h"
+#include "remoting/jingle_glue/jingle_thread.h"
+
+namespace remoting {
+
+// A class that manages threads and running context for the chromoting client
+// process.
+class ClientContext {
+ public:
+ ClientContext();
+ virtual ~ClientContext();
+
+ void Start();
+ void Stop();
+
+ JingleThread* jingle_thread();
+ MessageLoop* jingle_message_loop();
+
+ MessageLoop* main_message_loop();
+ MessageLoop* decode_message_loop();
+
+ private:
+ // A thread that handles Jingle network operations (used in
+ // JingleHostConnection).
+ JingleThread jingle_thread_;
+
+ // A thread that handles capture rate control and sending data to the
+ // HostConnection.
+ base::Thread main_thread_;
+
+ // A thread that handles all decode operations.
+ base::Thread decode_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientContext);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_CLIENT_CONTEXT_H_
diff --git a/remoting/client/client_util.cc b/remoting/client/client_util.cc
index ddaee42..9e53682 100644
--- a/remoting/client/client_util.cc
+++ b/remoting/client/client_util.cc
@@ -4,20 +4,26 @@
#include "remoting/client/client_util.h"
-#include <iostream>
+#include <string>
+#include <vector>
#include "base/logging.h"
+#include "base/string_util.h"
+#include "remoting/client/client_config.h"
+
+using std::string;
+using std::vector;
namespace remoting {
// Get host JID from command line arguments, or stdin if not specified.
-bool GetLoginInfo(int argc, char** argv,
- std::string* host_jid,
- std::string* username,
- std::string* auth_token) {
+bool GetLoginInfoFromArgs(int argc, char** argv, ClientConfig* config) {
bool found_host_jid = false;
bool found_jid = false;
bool found_auth_token = false;
+ string host_jid;
+ string username;
+ string auth_token;
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
@@ -27,14 +33,14 @@ bool GetLoginInfo(int argc, char** argv,
<< std::endl;
} else {
found_host_jid = true;
- *host_jid = argv[i];
+ host_jid = argv[i];
}
} else if (arg == "--jid") {
if (++i >= argc) {
LOG(WARNING) << "Expected JID to follow --jid option" << std::endl;
} else {
found_jid = true;
- *username = argv[i];
+ username = argv[i];
}
} else if (arg == "--token") {
if (++i >= argc) {
@@ -42,7 +48,7 @@ bool GetLoginInfo(int argc, char** argv,
<< std::endl;
} else {
found_auth_token = true;
- *auth_token = argv[i];
+ auth_token = argv[i];
}
} else {
LOG(WARNING) << "Unrecognized option: " << arg << std::endl;
@@ -50,44 +56,63 @@ bool GetLoginInfo(int argc, char** argv,
}
if (!found_host_jid) {
- std::cout << "Host JID: ";
- std::cin >> *host_jid;
- std::cin.ignore(); // Consume the leftover '\n'
+ return false;
}
// Validate the chromoting host JID.
- if (host_jid->find("/chromoting") == std::string::npos) {
- std::cerr << "Error: Expected Host JID in format: <jid>/chromoting<id>"
- << std::endl;
+ if (host_jid.find("/chromoting") == std::string::npos) {
return false;
}
if (!found_jid) {
- // Get username (JID).
- // Extract default JID from host_jid.
- std::string default_username;
- size_t jid_end = host_jid->find('/');
- if (jid_end != std::string::npos) {
- default_username = host_jid->substr(0, jid_end);
- }
- std::cout << "JID [" << default_username << "]: ";
- getline(std::cin, *username);
- if (username->length() == 0) {
- username->swap(default_username);
- }
- if (username->length() == 0) {
- std::cerr << "Error: Expected valid JID username" << std::endl;
- return false;
- }
+ return false;
}
if (!found_auth_token) {
- // Get authentication token.
- std::cout << "Auth token: ";
- getline(std::cin, *auth_token);
- std::cout << std::endl;
+ return false;
+ }
+
+ config->set_host_jid(host_jid);
+ config->set_username(username);
+ config->set_auth_token(auth_token);
+ return true;
+}
+
+// Get host JID from command line arguments, or stdin if not specified.
+bool GetLoginInfoFromUrlParams(const std::string& url, ClientConfig* config) {
+ // TODO(ajwong): We should use GURL or something. Don't parse this by hand!
+
+ // The Url should be of the form:
+ //
+ // chrome://remoting?user=<userid>&auth=<authtoken>&jid=<hostjid>
+ //
+ vector<string> parts;
+ SplitString(url, '&', &parts);
+ if (parts.size() != 3) {
+ return false;
+ }
+
+ size_t pos = parts[0].rfind('=');
+ if (pos == string::npos && (pos + 1) != string::npos) {
+ return false;
+ }
+ std::string username = parts[0].substr(pos + 1);
+
+ pos = parts[1].rfind('=');
+ if (pos == string::npos && (pos + 1) != string::npos) {
+ return false;
+ }
+ std::string auth_token = parts[1].substr(pos + 1);
+
+ pos = parts[2].rfind('=');
+ if (pos == string::npos && (pos + 1) != string::npos) {
+ return false;
}
+ std::string host_jid = parts[2].substr(pos + 1);
+ config->set_host_jid(host_jid);
+ config->set_username(username);
+ config->set_auth_token(auth_token);
return true;
}
diff --git a/remoting/client/client_util.h b/remoting/client/client_util.h
index 44f3435..9aa1474 100644
--- a/remoting/client/client_util.h
+++ b/remoting/client/client_util.h
@@ -9,12 +9,16 @@
namespace remoting {
+class ClientConfig;
+
// Get the login info from the cmdline args (or request from the console if
-// not present) and write values into |host_jid|, |username| and |auth_token|.
+// not present) and write values into |config|.
+// Return true if successful.
+bool GetLoginInfoFromArgs(int argc, char** argv, ClientConfig* config);
+
+// Get the login info from the URL params and write values into |config|.
// Return true if successful.
-bool GetLoginInfo(int argc, char** argv,
- std::string* host_jid, std::string* username,
- std::string* auth_token);
+bool GetLoginInfoFromUrlParams(const std::string& url, ClientConfig* config);
} // namespace remoting
diff --git a/remoting/client/client_util_unittest.cc b/remoting/client/client_util_unittest.cc
new file mode 100644
index 0000000..d9f2e7c
--- /dev/null
+++ b/remoting/client/client_util_unittest.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "remoting/client/client_config.h"
+#include "remoting/client/client_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+// TODO(ajwong): Once ChromotingPlugin stablizes a little more, come up with
+// sane unittests.
+class ClientUtilTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+};
+
+TEST_F(ClientUtilTest, GetLoginInfoFromUrlParams) {
+ const char url[] = "chromotocol://hostid?user=auser&auth=someauth&jid=ajid";
+ std::string user_id;
+ std::string auth_token;
+ std::string host_jid;
+ ClientConfig config;
+
+ ASSERT_TRUE(
+ GetLoginInfoFromUrlParams(url, &config));
+
+ EXPECT_EQ("auser", config.username());
+ EXPECT_EQ("someauth", config.auth_token());
+ EXPECT_EQ("ajid", config.host_jid());
+}
+
+} // namespace remoting
diff --git a/remoting/client/host_connection.h b/remoting/client/host_connection.h
index 0667cc9..c53bc73 100644
--- a/remoting/client/host_connection.h
+++ b/remoting/client/host_connection.h
@@ -11,6 +11,8 @@
namespace remoting {
+class ClientConfig;
+
class HostConnection {
public:
class HostEventCallback {
@@ -37,9 +39,7 @@ class HostConnection {
virtual ~HostConnection() {}
// TODO(ajwong): We need to generalize this API.
- virtual void Connect(const std::string& username,
- const std::string& auth_token,
- const std::string& host_jid,
+ virtual void Connect(ClientConfig* config,
HostEventCallback* event_callback) = 0;
virtual void Disconnect() = 0;
diff --git a/remoting/client/input_handler.h b/remoting/client/input_handler.h
new file mode 100644
index 0000000..fad3718
--- /dev/null
+++ b/remoting/client/input_handler.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_INPUT_HANDLER_H_
+#define REMOTING_CLIENT_INPUT_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/task.h"
+
+namespace remoting {
+
+class InputHandler {
+ public:
+ InputHandler() {}
+ virtual ~InputHandler() {}
+
+ virtual void Initialize() = 0;
+
+ protected:
+ DISALLOW_COPY_AND_ASSIGN(InputHandler);
+};
+
+} // namespace remoting
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::InputHandler);
+
+#endif // REMOTING_CLIENT_INPUT_HANDLER_H_
diff --git a/remoting/client/jingle_host_connection.cc b/remoting/client/jingle_host_connection.cc
index 9bf547f..2e1b0a1 100644
--- a/remoting/client/jingle_host_connection.cc
+++ b/remoting/client/jingle_host_connection.cc
@@ -4,28 +4,26 @@
#include "base/message_loop.h"
#include "remoting/base/constants.h"
+#include "remoting/client/client_config.h"
#include "remoting/client/jingle_host_connection.h"
#include "remoting/jingle_glue/jingle_thread.h"
namespace remoting {
-JingleHostConnection::JingleHostConnection(JingleThread* network_thread)
- : network_thread_(network_thread),
+JingleHostConnection::JingleHostConnection(ClientContext* context)
+ : context_(context),
event_callback_(NULL) {
}
JingleHostConnection::~JingleHostConnection() {
}
-void JingleHostConnection::Connect(const std::string& username,
- const std::string& password,
- const std::string& host_jid,
+void JingleHostConnection::Connect(ClientConfig* config,
HostEventCallback* event_callback) {
message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &JingleHostConnection::DoConnect,
- username, password, host_jid,
- event_callback));
+ config, event_callback));
}
void JingleHostConnection::Disconnect() {
@@ -105,20 +103,19 @@ void JingleHostConnection::OnNewConnection(
}
MessageLoop* JingleHostConnection::message_loop() {
- return network_thread_->message_loop();
+ return context_->jingle_thread()->message_loop();
}
-void JingleHostConnection::DoConnect(const std::string& username,
- const std::string& auth_token,
- const std::string& host_jid,
+void JingleHostConnection::DoConnect(ClientConfig* config,
HostEventCallback* event_callback) {
DCHECK_EQ(message_loop(), MessageLoop::current());
event_callback_ = event_callback;
- jingle_client_ = new JingleClient(network_thread_);
- jingle_client_->Init(username, auth_token, kChromotingTokenServiceName, this);
- jingle_channel_ = jingle_client_->Connect(host_jid, this);
+ jingle_client_ = new JingleClient(context_->jingle_thread());
+ jingle_client_->Init(config->username(), config->auth_token(),
+ kChromotingTokenServiceName, this);
+ jingle_channel_ = jingle_client_->Connect(config->host_jid(), this);
}
void JingleHostConnection::DoDisconnect() {
diff --git a/remoting/client/jingle_host_connection.h b/remoting/client/jingle_host_connection.h
index 96178aa..5fc75cb 100644
--- a/remoting/client/jingle_host_connection.h
+++ b/remoting/client/jingle_host_connection.h
@@ -22,6 +22,7 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "remoting/base/protocol_decoder.h"
+#include "remoting/client/client_context.h"
#include "remoting/client/host_connection.h"
#include "remoting/jingle_glue/jingle_channel.h"
#include "remoting/jingle_glue/jingle_client.h"
@@ -30,18 +31,17 @@ class MessageLoop;
namespace remoting {
+class ClientConfig;
class JingleThread;
class JingleHostConnection : public HostConnection,
public JingleChannel::Callback,
public JingleClient::Callback {
public:
- explicit JingleHostConnection(JingleThread* network_thread);
+ explicit JingleHostConnection(ClientContext* context);
virtual ~JingleHostConnection();
- virtual void Connect(const std::string& username,
- const std::string& auth_token,
- const std::string& host_jid,
+ virtual void Connect(ClientConfig* config,
HostEventCallback* event_callback);
virtual void Disconnect();
@@ -61,13 +61,11 @@ class JingleHostConnection : public HostConnection,
private:
MessageLoop* message_loop();
- void DoConnect(const std::string& username,
- const std::string& auth_token,
- const std::string& host_jid,
+ void DoConnect(ClientConfig* config,
HostEventCallback* event_callback);
void DoDisconnect();
- JingleThread* network_thread_;
+ ClientContext* context_;
scoped_refptr<JingleClient> jingle_client_;
scoped_refptr<JingleChannel> jingle_channel_;
diff --git a/remoting/client/plugin/chromoting_plugin.cc b/remoting/client/plugin/chromoting_plugin.cc
index 160bf3a..bb1aa80 100644
--- a/remoting/client/plugin/chromoting_plugin.cc
+++ b/remoting/client/plugin/chromoting_plugin.cc
@@ -10,18 +10,18 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "remoting/client/client_config.h"
+#include "remoting/client/client_util.h"
#include "remoting/client/chromoting_client.h"
#include "remoting/client/host_connection.h"
#include "remoting/client/jingle_host_connection.h"
+#include "remoting/client/plugin/pepper_input_handler.h"
#include "remoting/client/plugin/pepper_view.h"
#include "remoting/jingle_glue/jingle_thread.h"
#include "third_party/ppapi/c/pp_event.h"
#include "third_party/ppapi/c/pp_rect.h"
#include "third_party/ppapi/cpp/completion_callback.h"
-using std::string;
-using std::vector;
-
namespace remoting {
const char* ChromotingPlugin::kMimeType = "pepper-application/x-chromoting";
@@ -32,18 +32,17 @@ ChromotingPlugin::ChromotingPlugin(PP_Instance pp_instance)
}
ChromotingPlugin::~ChromotingPlugin() {
- if (host_connection_.get())
- host_connection_->Disconnect();
+ if (client_.get()) {
+ client_->Stop();
+ }
// TODO(ajwong): We need to ensure all objects have actually stopped posting
// to the message loop before this point. Right now, we don't have a well
// defined stop for the plugin process, and the thread shutdown is likely a
// race condition.
- if (network_thread_.get())
- network_thread_->Stop();
-
- if (main_thread_.get())
- main_thread_->Stop();
+ if (context_.get()) {
+ context_->Stop();
+ }
}
bool ChromotingPlugin::Init(uint32_t argc,
@@ -77,34 +76,29 @@ bool ChromotingPlugin::Init(uint32_t argc,
return false;
}
- string user_id;
- string auth_token;
- string host_jid;
- if (!ParseUrl(url, &user_id, &auth_token, &host_jid)) {
+ ClientConfig config;
+ if (!GetLoginInfoFromUrlParams(url, &config)) {
LOG(WARNING) << "Could not parse URL: " << url;
return false;
}
- // Start the threads.
- main_thread_.reset(new base::Thread("ChromoClientMain"));
- if (!main_thread_->Start()) {
- LOG(ERROR) << "Main thread failed to start.";
- return false;
- }
- network_thread_.reset(new JingleThread());
- network_thread_->Start();
-
- // Create the chromting objects.
- host_connection_.reset(new JingleHostConnection(network_thread_.get()));
+ // Create the chromoting objects.
+ host_connection_.reset(new JingleHostConnection(context_.get()));
view_.reset(new PepperView(this));
- client_.reset(new ChromotingClient(main_thread_->message_loop(),
- host_connection_.get(), view_.get()));
+ input_handler_.reset(new PepperInputHandler());
+ client_.reset(new ChromotingClient(&config,
+ context_.get(),
+ host_connection_.get(),
+ view_.get(),
+ input_handler_.get(),
+ NULL));
// Default to a medium grey.
view_->SetSolidFill(0xFFCDCDCD);
// Kick off the connection.
- host_connection_->Connect(user_id, auth_token, host_jid, client_.get());
+ context_->Start();
+ client_->Start();
return true;
}
@@ -153,41 +147,4 @@ bool ChromotingPlugin::HandleEvent(const PP_Event& event) {
return false;
}
-bool ChromotingPlugin::ParseUrl(const std::string& url,
- string* user_id,
- string* auth_token,
- string* host_jid) {
- // TODO(ajwong): We should use GURL or something. Don't parse this by hand!
-
- // The Url should be of the form:
- //
- // chromotocol://<hostid>?user=<userid>&auth=<authtoken>&jid=<hostjid>
- //
- vector<string> parts;
- SplitString(url, '&', &parts);
- if (parts.size() != 3) {
- return false;
- }
-
- size_t pos = parts[0].rfind('=');
- if (pos == string::npos && (pos + 1) != string::npos) {
- return false;
- }
- user_id->assign(parts[0].substr(pos + 1));
-
- pos = parts[1].rfind('=');
- if (pos == string::npos && (pos + 1) != string::npos) {
- return false;
- }
- auth_token->assign(parts[1].substr(pos + 1));
-
- pos = parts[2].rfind('=');
- if (pos == string::npos && (pos + 1) != string::npos) {
- return false;
- }
- host_jid->assign(parts[2].substr(pos + 1));
-
- return true;
-}
-
} // namespace remoting
diff --git a/remoting/client/plugin/chromoting_plugin.h b/remoting/client/plugin/chromoting_plugin.h
index 0aac051..3bd0470 100644
--- a/remoting/client/plugin/chromoting_plugin.h
+++ b/remoting/client/plugin/chromoting_plugin.h
@@ -34,7 +34,9 @@ class Module;
namespace remoting {
class ChromotingClient;
+class ClientContext;
class HostConnection;
+class InputHandler;
class JingleThread;
class PepperView;
@@ -56,11 +58,6 @@ class ChromotingPlugin : public pp::Instance {
FRIEND_TEST(ChromotingPluginTest, ParseUrl);
FRIEND_TEST(ChromotingPluginTest, TestCaseSetup);
- static bool ParseUrl(const std::string& url,
- std::string* user_id,
- std::string* auth_token,
- std::string* host_jid);
-
// Since we're an internal plugin, we can just grab the message loop during
// init to figure out which thread we're on. This should only be used to
// sanity check which thread we're executing on. Do not post task here!
@@ -69,11 +66,14 @@ class ChromotingPlugin : public pp::Instance {
// TODO(ajwong): Think if there is a better way to safeguard this.
MessageLoop* pepper_main_loop_dont_post_to_me_;
- scoped_ptr<base::Thread> main_thread_;
- scoped_ptr<JingleThread> network_thread_;
+ scoped_ptr<ClientContext> context_;
scoped_ptr<HostConnection> host_connection_;
+
scoped_ptr<PepperView> view_;
+
+ scoped_ptr<InputHandler> input_handler_;
+
scoped_ptr<ChromotingClient> client_;
DISALLOW_COPY_AND_ASSIGN(ChromotingPlugin);
diff --git a/remoting/client/plugin/chromoting_plugin_unittest.cc b/remoting/client/plugin/chromoting_plugin_unittest.cc
index edda0e3..2dc0358 100644
--- a/remoting/client/plugin/chromoting_plugin_unittest.cc
+++ b/remoting/client/plugin/chromoting_plugin_unittest.cc
@@ -17,17 +17,4 @@ class ChromotingPluginTest : public testing::Test {
}
};
-TEST_F(ChromotingPluginTest, ParseUrl) {
- const char url[] = "chromotocol://hostid?user=auser&auth=someauth&jid=ajid";
- std::string user_id;
- std::string auth_token;
- std::string host_jid;
- ASSERT_TRUE(
- ChromotingPlugin::ParseUrl(url, &user_id, &auth_token, &host_jid));
-
- EXPECT_EQ("auser", user_id);
- EXPECT_EQ("someauth", auth_token);
- EXPECT_EQ("ajid", host_jid);
-}
-
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc
new file mode 100644
index 0000000..53cced3
--- /dev/null
+++ b/remoting/client/plugin/pepper_input_handler.cc
@@ -0,0 +1,19 @@
+// 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.
+
+#include "remoting/client/plugin/pepper_input_handler.h"
+
+namespace remoting {
+
+PepperInputHandler::PepperInputHandler() {
+}
+
+PepperInputHandler::~PepperInputHandler() {
+}
+
+void PepperInputHandler::Initialize() {
+ // TODO(garykac): Implement this.
+}
+
+} // namespace remoting
diff --git a/remoting/client/plugin/pepper_input_handler.h b/remoting/client/plugin/pepper_input_handler.h
new file mode 100644
index 0000000..59399e9
--- /dev/null
+++ b/remoting/client/plugin/pepper_input_handler.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_PLUGIN_PEPPER_INPUT_HANDLER_H_
+#define REMOTING_CLIENT_PLUGIN_PEPPER_INPUT_HANDLER_H_
+
+#include "remoting/client/input_handler.h"
+
+namespace remoting {
+
+class PepperInputHandler : public InputHandler {
+ public:
+ PepperInputHandler();
+ virtual ~PepperInputHandler();
+
+ void Initialize();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PepperInputHandler);
+};
+
+} // namespace remoting
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::PepperInputHandler);
+
+#endif // REMOTING_CLIENT_PLUGIN_PEPPER_INPUT_HANDLER_H_
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index a6ebc13..ce38289 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -30,6 +30,13 @@ PepperView::PepperView(ChromotingPlugin* plugin)
PepperView::~PepperView() {
}
+bool PepperView::Initialize() {
+ return true;
+}
+
+void PepperView::TearDown() {
+}
+
void PepperView::Paint() {
if (!plugin_->CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewRunnableMethod(this, &PepperView::Paint));
@@ -118,10 +125,10 @@ void PepperView::SetViewport(int x, int y, int width, int height) {
}
}
-void PepperView::SetBackingStoreSize(int width, int height) {
+void PepperView::SetHostScreenSize(int width, int height) {
if (!plugin_->CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewRunnableMethod(this,
- &PepperView::SetBackingStoreSize,
+ &PepperView::SetHostScreenSize,
width, height));
return;
}
diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h
index 655b9ae..3622ab3 100644
--- a/remoting/client/plugin/pepper_view.h
+++ b/remoting/client/plugin/pepper_view.h
@@ -37,11 +37,13 @@ class PepperView : public ChromotingView {
virtual ~PepperView();
// ChromotingView implementation.
+ virtual bool Initialize();
+ virtual void TearDown();
virtual void Paint();
virtual void SetSolidFill(uint32 color);
virtual void UnsetSolidFill();
virtual void SetViewport(int x, int y, int width, int height);
- virtual void SetBackingStoreSize(int width, int height);
+ virtual void SetHostScreenSize(int width, int height);
virtual void HandleBeginUpdateStream(HostMessage* msg);
virtual void HandleUpdateStreamPacket(HostMessage* msg);
virtual void HandleEndUpdateStream(HostMessage* msg);
diff --git a/remoting/client/simple_client.cc b/remoting/client/simple_client.cc
deleted file mode 100644
index d1dd6e2..0000000
--- a/remoting/client/simple_client.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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.
-
-// A simple client implements a minimal Chromoting client and shows
-// network traffic for debugging.
-
-#include <iostream>
-#include <list>
-
-#include "base/at_exit.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-
-#include "base/waitable_event.h"
-#include "media/base/data_buffer.h"
-#include "remoting/base/protocol_decoder.h"
-#include "remoting/client/client_util.h"
-#include "remoting/client/jingle_host_connection.h"
-#include "remoting/jingle_glue/jingle_client.h"
-#include "remoting/jingle_glue/jingle_thread.h"
-
-using remoting::BeginUpdateStreamMessage;
-using remoting::EndUpdateStreamMessage;
-using remoting::HostConnection;
-using remoting::HostMessage;
-using remoting::HostMessageList;
-using remoting::InitClientMessage;
-using remoting::JingleClient;
-using remoting::JingleHostConnection;
-using remoting::JingleThread;
-using remoting::ProtocolDecoder;
-using remoting::UpdateStreamPacketMessage;
-
-class SimpleHostEventCallback : public HostConnection::HostEventCallback {
- public:
- explicit SimpleHostEventCallback(MessageLoop* loop,
- base::WaitableEvent* client_done)
- : main_loop_(loop), client_done_(client_done) {
- }
-
- virtual void HandleMessages(HostConnection* conn,
- HostMessageList* messages) {
- HostMessageList list;
- messages->swap(list);
- for (size_t i = 0; i < list.size(); ++i) {
- HostMessage* msg = list[i];
- if (msg->has_init_client()) {
- HandleInitClientMessage(msg);
- } else if (msg->has_begin_update_stream()) {
- HandleBeginUpdateStreamMessage(msg);
- } else if (msg->has_update_stream_packet()) {
- HandleUpdateStreamPacketMessage(msg);
- } else if (msg->has_end_update_stream()) {
- HandleEndUpdateStreamMessage(msg);
- }
- }
- STLDeleteElements<HostMessageList>(&list);
- }
-
- virtual void OnConnectionOpened(HostConnection* conn) {
- std::cout << "Connection establised." << std::endl;
- }
-
- virtual void OnConnectionClosed(HostConnection* conn) {
- std::cout << "Connection closed." << std::endl;
- client_done_->Signal();
- }
-
- virtual void OnConnectionFailed(HostConnection* conn) {
- std::cout << "Conection failed." << std::endl;
- client_done_->Signal();
- }
-
- private:
- void HandleInitClientMessage(HostMessage* host_msg) {
- const InitClientMessage& msg = host_msg->init_client();
- std::cout << "InitClient (" << msg.width()
- << ", " << msg.height() << ")" << std::endl;
- }
-
- void HandleBeginUpdateStreamMessage(HostMessage* host_msg) {
- const BeginUpdateStreamMessage& msg = host_msg->begin_update_stream();
- std::cout << msg.GetTypeName() << std::endl;
- }
-
- void HandleUpdateStreamPacketMessage(HostMessage* host_msg) {
- const UpdateStreamPacketMessage& msg = host_msg->update_stream_packet();
- if (!msg.has_begin_rect())
- return;
-
- std::cout << "UpdateStreamPacket (" << msg.begin_rect().x()
- << ", " << msg.begin_rect().y() << ") ["
- << msg.begin_rect().width() << " x "
- << msg.begin_rect().height() << "]"
- << std::endl;
- }
-
- void HandleEndUpdateStreamMessage(HostMessage* host_msg) {
- const EndUpdateStreamMessage& msg = host_msg->end_update_stream();
- std::cout << msg.GetTypeName() << std::endl;
- }
-
- // JingleClient::Callback interface.
- void OnStateChange(JingleClient* client, JingleClient::State state) {
- if (state == JingleClient::CONNECTED) {
- LOG(INFO) << "Connected as: " << client->GetFullJid();
- } else if (state == JingleClient::CLOSED) {
- LOG(INFO) << "Connection closed.";
- }
- }
-
- MessageLoop* main_loop_;
- base::WaitableEvent* client_done_;
-
- DISALLOW_COPY_AND_ASSIGN(SimpleHostEventCallback);
-};
-
-int main(int argc, char** argv) {
- base::AtExitManager exit_manager;
- std::string host_jid;
- std::string username;
- std::string auth_token;
-
- if (!remoting::GetLoginInfo(argc, argv, &host_jid, &username, &auth_token)) {
- std::cerr << "Cannot get valid login info." << std::endl;
- return 1;
- }
-
- // Start up a thread to run everything.
- JingleThread network_thread;
- network_thread.Start();
-
- base::WaitableEvent client_done(false, false);
- SimpleHostEventCallback handler(network_thread.message_loop(), &client_done);
- JingleHostConnection connection(&network_thread);
- connection.Connect(username, auth_token, host_jid, &handler);
-
- // Wait until the mainloop has been signaled to exit.
- client_done.Wait();
-
- connection.Disconnect();
- network_thread.message_loop()->PostTask(FROM_HERE,
- new MessageLoop::QuitTask());
- network_thread.Stop();
-
- return 0;
-}
diff --git a/remoting/client/x11_client.cc b/remoting/client/x11_client.cc
index eeda70d..8d79f92 100644
--- a/remoting/client/x11_client.cc
+++ b/remoting/client/x11_client.cc
@@ -2,259 +2,46 @@
// 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.
+// This file implements a simple X11 chromoting client.
#include <iostream>
#include "base/at_exit.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-#include "base/task.h"
-#include "base/waitable_event.h"
+#include "remoting/client/chromoting_client.h"
+#include "remoting/client/client_config.h"
#include "remoting/client/client_util.h"
-#include "remoting/client/host_connection.h"
#include "remoting/client/jingle_host_connection.h"
-#include "remoting/jingle_glue/jingle_thread.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>
-
-using remoting::JingleHostConnection;
-using remoting::JingleThread;
-
-namespace remoting {
-
-class X11Client : public HostConnection::HostEventCallback {
- public:
- X11Client(MessageLoop* loop, base::WaitableEvent* client_done)
- : message_loop_(loop),
- client_done_(client_done),
- display_(NULL),
- window_(0),
- width_(0),
- height_(0) {
- }
-
- virtual ~X11Client() {
- DCHECK(!display_);
- DCHECK(!window_);
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // 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 established." << std::endl;
- }
-
- virtual void OnConnectionClosed(HostConnection* conn) {
- std::cout << "Connection closed." << std::endl;
- client_done_->Signal();
- }
-
- virtual void OnConnectionFailed(HostConnection* conn) {
- std::cout << "Conection failed." << std::endl;
- client_done_->Signal();
- }
-
- void InitX11() {
- message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &X11Client::DoInitX11));
- }
-
- void DoInitX11() {
- display_ = XOpenDisplay(NULL);
- if (!display_) {
- std::cout << "Error - cannot open display" << std::endl;
- client_done_->Signal();
- return;
- }
-
- // 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 DestroyX11() {
- message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &X11Client::DoDestroyX11));
- }
-
- void DoDestroyX11() {
- if (display_ && window_) {
- // Shutdown the window system.
- XDestroyWindow(display_, window_);
- XCloseDisplay(display_);
- display_ = NULL;
- window_ = 0;
- }
- }
-
- private:
- // 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 received: " << width_ << "x" << height_;
- XResizeWindow(display_, window_, width_, height_);
+#include "remoting/client/x11_input_handler.h"
- // Now construct the X11View that renders the remote desktop.
- view_.reset(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);
- }
-
- MessageLoop* message_loop_;
- base::WaitableEvent* client_done_;
-
- // Members used for display.
- Display* display_;
- Window window_;
-
- // Dimension of the window. They are initialized when InitClient message is
- // received.
- int width_;
- int height_;
-
- scoped_ptr<ChromotingView> view_;
-
- DISALLOW_COPY_AND_ASSIGN(X11Client);
-};
-
-} // namespace remoting
-
-DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::X11Client);
+void ClientQuit(MessageLoop* loop) {
+ loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+}
int main(int argc, char** argv) {
base::AtExitManager at_exit;
- std::string host_jid;
- std::string username;
- std::string auth_token;
- if (!remoting::GetLoginInfo(argc, argv, &host_jid, &username, &auth_token)) {
- std::cout << "Cannot obtain login info" << std::endl;
+ remoting::ClientConfig config;
+ if (!remoting::GetLoginInfoFromArgs(argc, argv, &config)) {
+ std::cout << "Unable to obtain login info" << std::endl;
return 1;
}
- JingleThread network_thread;
- network_thread.Start();
-
- base::WaitableEvent client_done(false, false);
- remoting::X11Client client(network_thread.message_loop(), &client_done);
- JingleHostConnection connection(&network_thread);
- connection.Connect(username, auth_token, host_jid, &client);
-
- client.InitX11();
-
- // Wait until the main loop is done.
- client_done.Wait();
-
- connection.Disconnect();
+ MessageLoop ui_loop;
+ remoting::ClientContext context;
+ remoting::JingleHostConnection connection(&context);
+ remoting::X11View view;
+ remoting::X11InputHandler input_handler(&context, &view);
+ remoting::ChromotingClient client(&config, &context, &connection, &view,
+ &input_handler, NewRunnableFunction(&ClientQuit, &ui_loop));
- client.DestroyX11();
+ // Run the client on a new MessageLoop until
+ context.Start();
+ client.Start();
+ ui_loop.Run();
- // Quit the current message loop.
- network_thread.message_loop()->PostTask(FROM_HERE,
- new MessageLoop::QuitTask());
- network_thread.Stop();
+ client.Stop();
+ context.Stop();
return 0;
}
diff --git a/remoting/client/x11_input_handler.cc b/remoting/client/x11_input_handler.cc
new file mode 100644
index 0000000..455ff61
--- /dev/null
+++ b/remoting/client/x11_input_handler.cc
@@ -0,0 +1,62 @@
+// 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.
+
+#include "remoting/client/x11_input_handler.h"
+
+#include "base/message_loop.h"
+#include "remoting/client/client_context.h"
+#include "remoting/client/x11_view.h"
+#include "remoting/jingle_glue/jingle_thread.h"
+
+// Include Xlib at the end because it clashes with ClientMessage defined in
+// the protocol buffer.
+#include <X11/Xlib.h>
+
+namespace remoting {
+
+X11InputHandler::X11InputHandler(ClientContext* context,
+ ChromotingView* view)
+ : context_(context),
+ view_(view) {
+}
+
+X11InputHandler::~X11InputHandler() {
+}
+
+void X11InputHandler::Initialize() {
+ ScheduleX11EventHandler();
+}
+
+void X11InputHandler::DoProcessX11Events() {
+ DCHECK_EQ(context_->jingle_thread()->message_loop(), MessageLoop::current());
+ Display* display = static_cast<X11View*>(view_)->display();
+ if (XPending(display)) {
+ XEvent e;
+ XNextEvent(display, &e);
+ if (e.type == Expose) {
+ // Tell the view 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 X11InputHandler::ScheduleX11EventHandler() {
+ // Schedule a delayed task to process X11 events in 10ms.
+ static const int kProcessEventsInterval = 10;
+ context_->jingle_thread()->message_loop()->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &X11InputHandler::DoProcessX11Events),
+ kProcessEventsInterval);
+}
+
+} // namespace remoting
diff --git a/remoting/client/x11_input_handler.h b/remoting/client/x11_input_handler.h
new file mode 100644
index 0000000..f4b4471
--- /dev/null
+++ b/remoting/client/x11_input_handler.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_X11_INPUT_HANDLER_H_
+#define REMOTING_CLIENT_X11_INPUT_HANDLER_H_
+
+#include "remoting/client/input_handler.h"
+
+namespace remoting {
+
+class ClientContext;
+class ChromotingView;
+
+class X11InputHandler : public InputHandler {
+ public:
+ X11InputHandler(ClientContext* context, ChromotingView* view);
+ virtual ~X11InputHandler();
+
+ void Initialize();
+
+ private:
+
+ void DoProcessX11Events();
+
+ void ScheduleX11EventHandler();
+
+ ClientContext* context_;
+ ChromotingView* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11InputHandler);
+};
+
+} // namespace remoting
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::X11InputHandler);
+
+#endif // REMOTING_CLIENT_X11_INPUT_HANDLER_H_
diff --git a/remoting/client/x11_view.cc b/remoting/client/x11_view.cc
index c5f9a88..e4b59ae 100644
--- a/remoting/client/x11_view.cc
+++ b/remoting/client/x11_view.cc
@@ -14,6 +14,14 @@
namespace remoting {
+X11View::X11View()
+ : display_(NULL),
+ window_(0),
+ width_(0),
+ height_(0),
+ picture_(0) {
+}
+
X11View::X11View(Display* display, XID window, int width, int height)
: display_(display),
window_(window),
@@ -26,9 +34,49 @@ X11View::X11View(Display* display, XID window, int width, int height)
}
X11View::~X11View() {
+ DCHECK(!display_);
+ DCHECK(!window_);
+}
+
+bool X11View::Initialize() {
+ display_ = XOpenDisplay(NULL);
+ if (!display_) {
+ return false;
+ }
+
+ // 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_);
+ return true;
+}
+
+void X11View::TearDown() {
+ if (display_ && window_) {
+ // Shutdown the window system.
+ XDestroyWindow(display_, window_);
+ XCloseDisplay(display_);
+ }
+ display_ = NULL;
+ window_ = 0;
}
void X11View::Paint() {
+ // Don't bother attempting to paint if the display hasn't been set up.
+ if (!display_ || !window_ || !height_ || !width_) {
+ return;
+ }
+
// TODO(hclam): Paint only the updated regions.
all_update_rects_.clear();
@@ -80,23 +128,24 @@ void X11View::Paint() {
}
void X11View::SetSolidFill(uint32 color) {
- // TODO(ajwong): Implement.
- NOTIMPLEMENTED();
+ // TODO(garykac): Implement.
+ // NOTIMPLEMENTED();
}
void X11View::UnsetSolidFill() {
- // TODO(ajwong): Implement.
- NOTIMPLEMENTED();
+ // TODO(garykac): Implement.
+ // NOTIMPLEMENTED();
}
void X11View::SetViewport(int x, int y, int width, int height) {
- // TODO(ajwong): Implement.
- NOTIMPLEMENTED();
+ // TODO(garykac): Implement.
+ // NOTIMPLEMENTED();
}
-void X11View::SetBackingStoreSize(int width, int height) {
- // TODO(ajwong): Implement.
- NOTIMPLEMENTED();
+void X11View::SetHostScreenSize(int width, int height) {
+ width_ = width;
+ height_ = height;
+ XResizeWindow(display_, window_, width_, height_);
}
void X11View::InitPaintTarget() {
diff --git a/remoting/client/x11_view.h b/remoting/client/x11_view.h
index 1a76cb3..73e63c7 100644
--- a/remoting/client/x11_view.h
+++ b/remoting/client/x11_view.h
@@ -19,20 +19,25 @@ namespace remoting {
// A ChromotingView implemented using X11 and XRender.
class X11View : public ChromotingView {
public:
+ X11View(); // Delete this.
X11View(Display* display, XID window, int width, int height);
virtual ~X11View();
// ChromotingView implementations.
+ virtual bool Initialize();
+ virtual void TearDown();
virtual void Paint();
virtual void SetSolidFill(uint32 color);
virtual void UnsetSolidFill();
virtual void SetViewport(int x, int y, int width, int height);
- virtual void SetBackingStoreSize(int width, int height);
+ virtual void SetHostScreenSize(int width, int height);
virtual void HandleBeginUpdateStream(HostMessage* msg);
virtual void HandleUpdateStreamPacket(HostMessage* msg);
virtual void HandleEndUpdateStream(HostMessage* msg) ;
+ Display* display() { return display_; }
+
private:
void InitPaintTarget();
void OnPartialDecodeDone();
diff --git a/remoting/host/chromoting_host_context.h b/remoting/host/chromoting_host_context.h
index f488f74..f4e2f8a 100644
--- a/remoting/host/chromoting_host_context.h
+++ b/remoting/host/chromoting_host_context.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_CHROMOTING_HOST_CONTEXT_H_
-#define REMOTING_CHROMOTING_HOST_CONTEXT_H_
+#ifndef REMOTING_HOST_CHROMOTING_HOST_CONTEXT_H_
+#define REMOTING_HOST_CHROMOTING_HOST_CONTEXT_H_
#include <string>
@@ -31,16 +31,16 @@ class ChromotingHostContext {
private:
FRIEND_TEST(ChromotingHostContextTest, StartAndStop);
- // A thread that host network operations.
+ // A thread that hosts all network operations.
JingleThread jingle_thread_;
- // A thread that host ChromotingHost.
+ // A thread that hosts ChromotingHost and performs rate control.
base::Thread main_thread_;
- // A thread that host all capture operations.
+ // A thread that hosts all capture operations.
base::Thread capture_thread_;
- // A thread that host all encode operations.
+ // A thread that hosts all encode operations.
base::Thread encode_thread_;
DISALLOW_COPY_AND_ASSIGN(ChromotingHostContext);
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index bda9e60..85718e3 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -51,6 +51,8 @@
},
'sources': [
'client/x11_client.cc',
+ 'client/x11_input_handler.cc',
+ 'client/x11_input_handler.h',
'client/x11_view.cc',
'client/x11_view.h',
],
@@ -79,6 +81,8 @@
'client/plugin/chromoting_plugin.h',
'client/plugin/pepper_entrypoints.cc',
'client/plugin/pepper_entrypoints.h',
+ 'client/plugin/pepper_input_handler.cc',
+ 'client/plugin/pepper_input_handler.h',
'client/plugin/pepper_view.cc',
'client/plugin/pepper_view.h',
'client/plugin/pepper_util.cc',
@@ -222,12 +226,16 @@
'client/chromoting_client.cc',
'client/chromoting_client.h',
'client/chromoting_view.h',
+ 'client/client_config.h',
+ 'client/client_context.cc',
+ 'client/client_context.h',
'client/client_util.cc',
'client/client_util.h',
'client/decoder.h',
'client/decoder_verbatim.cc',
'client/decoder_verbatim.h',
'client/host_connection.h',
+ 'client/input_handler.h',
'client/jingle_host_connection.cc',
'client/jingle_host_connection.h',
],
@@ -263,20 +271,7 @@
'sources': [
'host/keygen_main.cc',
],
- }, # end of target 'chromoting_simple_host'
-
- {
- 'target_name': 'chromoting_simple_client',
- 'type': 'executable',
- 'dependencies': [
- 'chromoting_base',
- 'chromoting_client',
- 'chromoting_jingle_glue',
- ],
- 'sources': [
- 'client/simple_client.cc',
- ],
- }, # end of target 'chromoting_simple_client'
+ }, # end of target 'chromoting_host_keygen'
{
'target_name': 'chromoting_jingle_glue',