summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-17 17:06:32 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-17 17:06:32 +0000
commitfc232b598c601e066f6a17b5c647b1e30667f38e (patch)
treebc7bb8d459caaed60ddc882d9aa66caa4bedacd0 /remoting
parentc1e0696a17d2683b191ebc9b3b5233260c12c3db (diff)
downloadchromium_src-fc232b598c601e066f6a17b5c647b1e30667f38e.zip
chromium_src-fc232b598c601e066f6a17b5c647b1e30667f38e.tar.gz
chromium_src-fc232b598c601e066f6a17b5c647b1e30667f38e.tar.bz2
Hookup the ChromotingPlugin into the refactored implementation
of HostConnection and ChromotingView. Also implement a bare-bones PepperView. No unittests yet. Still too in flux to be worth it. BUG=none TEST=none Review URL: http://codereview.chromium.org/2852003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50116 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/client/chromoting_client.cc170
-rw-r--r--remoting/client/chromoting_client.h78
-rw-r--r--remoting/client/chromoting_view.h21
-rw-r--r--remoting/client/host_connection.h3
-rw-r--r--remoting/client/jingle_host_connection.cc20
-rw-r--r--remoting/client/jingle_host_connection.h20
-rw-r--r--remoting/client/plugin/chromoting_main.cc2
-rw-r--r--remoting/client/plugin/chromoting_plugin.cc116
-rw-r--r--remoting/client/plugin/chromoting_plugin.h69
-rw-r--r--remoting/client/plugin/chromoting_plugin_unittest.cc51
-rw-r--r--remoting/client/plugin/pepper_view.cc154
-rw-r--r--remoting/client/plugin/pepper_view.h77
-rw-r--r--remoting/client/simple_client.cc7
-rw-r--r--remoting/client/x11_client.cc23
-rw-r--r--remoting/client/x11_view.cc22
-rw-r--r--remoting/client/x11_view.h6
-rw-r--r--remoting/remoting.gyp59
-rw-r--r--remoting/tools/client_webserver/main.c5
18 files changed, 785 insertions, 118 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
new file mode 100644
index 0000000..cad1993
--- /dev/null
+++ b/remoting/client/chromoting_client.cc
@@ -0,0 +1,170 @@
+// 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/chromoting_client.h"
+
+#include "base/message_loop.h"
+#include "remoting/client/chromoting_view.h"
+#include "remoting/client/host_connection.h"
+
+static const uint32 kCreatedColor = 0xff0000ff;
+static const uint32 kDisconnectedColor = 0xff00ff00;
+static const uint32 kFailedColor = 0xffff0000;
+
+namespace remoting {
+
+ChromotingClient::ChromotingClient(MessageLoop* message_loop,
+ HostConnection* connection,
+ ChromotingView* view)
+ : message_loop_(message_loop),
+ state_(CREATED),
+ host_connection_(connection),
+ view_(view) {
+}
+
+ChromotingClient::~ChromotingClient() {
+}
+
+void ChromotingClient::Repaint() {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::DoRepaint));
+}
+
+void ChromotingClient::SetViewport(int x, int y, int width, int height) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::DoSetViewport,
+ x, y, width, height));
+}
+
+void ChromotingClient::HandleMessages(HostConnection* conn,
+ HostMessageList* messages) {
+ 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));
+ } else if (msg->has_begin_update_stream()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::DoBeginUpdate, msg));
+ } else if (msg->has_update_stream_packet()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::DoHandleUpdate, msg));
+ } else if (msg->has_end_update_stream()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::DoEndUpdate, msg));
+ } else {
+ NOTREACHED() << "Unknown message received";
+ }
+ }
+ // Assume we have processed all the messages.
+ messages->clear();
+}
+
+void ChromotingClient::OnConnectionOpened(HostConnection* conn) {
+ LOG(INFO) << "ChromotingClient::OnConnectionOpened";
+ SetState(CONNECTED);
+}
+
+void ChromotingClient::OnConnectionClosed(HostConnection* conn) {
+ LOG(INFO) << "ChromotingClient::OnConnectionClosed";
+ SetState(DISCONNECTED);
+}
+
+void ChromotingClient::OnConnectionFailed(HostConnection* conn) {
+ LOG(INFO) << "ChromotingClient::OnConnectionFailed";
+ SetState(FAILED);
+}
+
+MessageLoop* ChromotingClient::message_loop() {
+ return 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());
+
+ state_ = s;
+ switch (state_) {
+ case CREATED:
+ view_->SetSolidFill(kCreatedColor);
+ break;
+
+ case CONNECTED:
+ view_->UnsetSolidFill();
+ break;
+
+ case DISCONNECTED:
+ view_->SetSolidFill(kDisconnectedColor);
+ break;
+
+ case FAILED:
+ view_->SetSolidFill(kFailedColor);
+ break;
+ }
+
+ DoRepaint();
+}
+
+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) {
+ DCHECK_EQ(message_loop(), MessageLoop::current());
+ DCHECK(msg->has_init_client());
+ scoped_ptr<HostMessage> deleter(msg);
+
+ // Saves the dimension and 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);
+}
+
+void ChromotingClient::DoBeginUpdate(HostMessage* msg) {
+ DCHECK_EQ(message_loop(), MessageLoop::current());
+ DCHECK(msg->has_begin_update_stream());
+
+ view_->HandleBeginUpdateStream(msg);
+}
+
+void ChromotingClient::DoHandleUpdate(HostMessage* msg) {
+ DCHECK_EQ(message_loop(), MessageLoop::current());
+ DCHECK(msg->has_update_stream_packet());
+
+ view_->HandleUpdateStreamPacket(msg);
+}
+
+void ChromotingClient::DoEndUpdate(HostMessage* msg) {
+ DCHECK_EQ(message_loop(), MessageLoop::current());
+ DCHECK(msg->has_update_stream_packet());
+
+ view_->HandleUpdateStreamPacket(msg);
+}
+
+} // namespace remoting
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
new file mode 100644
index 0000000..587f1fb
--- /dev/null
+++ b/remoting/client/chromoting_client.h
@@ -0,0 +1,78 @@
+// 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.
+
+// ChromotingClient is the controller for the Client implementation.
+
+#ifndef REMOTING_CLIENT_CHROMOTING_CLIENT_H
+#define REMOTING_CLIENT_CHROMOTING_CLIENT_H
+
+#include "base/task.h"
+#include "remoting/client/host_connection.h"
+
+class MessageLoop;
+
+namespace remoting {
+
+class ChromotingView;
+
+class ChromotingClient : public HostConnection::HostEventCallback {
+ public:
+ ChromotingClient(MessageLoop* message_loop,
+ HostConnection* connection,
+ ChromotingView* view);
+ virtual ~ChromotingClient();
+
+ // Signals that the associated view may need updating.
+ virtual void Repaint();
+
+ // Sets the viewport to do display. The viewport may be larger and/or
+ // smaller than the actual image background being displayed.
+ virtual void SetViewport(int x, int y, int width, int height);
+
+ // HostConnection::HostEventCallback implementation.
+ virtual void HandleMessages(HostConnection* conn, HostMessageList* messages);
+ virtual void OnConnectionOpened(HostConnection* conn);
+ virtual void OnConnectionClosed(HostConnection* conn);
+ virtual void OnConnectionFailed(HostConnection* conn);
+
+ private:
+ enum State {
+ CREATED,
+ CONNECTED,
+ DISCONNECTED,
+ FAILED,
+ };
+
+ MessageLoop* message_loop();
+
+ // 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);
+
+ MessageLoop* message_loop_;
+
+ State state_;
+
+ // Connection to views and hosts. Not owned.
+ HostConnection* host_connection_;
+ ChromotingView* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromotingClient);
+};
+
+} // namespace remoting
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::ChromotingClient);
+
+#endif // REMOTING_CLIENT_CHROMOTING_CLIENT_H
diff --git a/remoting/client/chromoting_view.h b/remoting/client/chromoting_view.h
index cf70b99..503a903 100644
--- a/remoting/client/chromoting_view.h
+++ b/remoting/client/chromoting_view.h
@@ -14,7 +14,7 @@ class HostMessage;
// ChromotingView defines the behavior of an object that draws a view of the
// remote desktop. Its main function is to choose the right decoder and render
// the update stream onto the screen.
-class ChromotingView : public base::RefCountedThreadSafe<ChromotingView> {
+class ChromotingView {
public:
virtual ~ChromotingView() {}
@@ -22,6 +22,25 @@ class ChromotingView : public base::RefCountedThreadSafe<ChromotingView> {
// TODO(hclam): Add rects as parameter if needed.
virtual void Paint() = 0;
+ // Fill the screen with one single static color, and ignore updates.
+ // Useful for debugging.
+ virtual void SetSolidFill(uint32 color) = 0;
+
+ // Removes a previously set solid fill. If no fill was previous set, this
+ // does nothing.
+ virtual void UnsetSolidFill() = 0;
+
+ // Reposition and resize the viewport into the backing store. If the viewport
+ // 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.
+ //
+ // TODO(ajwong): We need a better name. Look at how Java represents this
+ // stuff?
+ virtual void SetBackingStoreSize(int width, int height) = 0;
+
// Handle the BeginUpdateStream message.
virtual void HandleBeginUpdateStream(HostMessage* msg) = 0;
diff --git a/remoting/client/host_connection.h b/remoting/client/host_connection.h
index adbb876..0667cc9 100644
--- a/remoting/client/host_connection.h
+++ b/remoting/client/host_connection.h
@@ -39,7 +39,8 @@ class 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) = 0;
+ const std::string& host_jid,
+ HostEventCallback* event_callback) = 0;
virtual void Disconnect() = 0;
protected:
diff --git a/remoting/client/jingle_host_connection.cc b/remoting/client/jingle_host_connection.cc
index 7b9241c..9bf547f 100644
--- a/remoting/client/jingle_host_connection.cc
+++ b/remoting/client/jingle_host_connection.cc
@@ -9,9 +9,9 @@
namespace remoting {
-JingleHostConnection::JingleHostConnection(JingleThread* network_thread,
- HostEventCallback* event_callback)
- : network_thread_(network_thread), event_callback_(event_callback) {
+JingleHostConnection::JingleHostConnection(JingleThread* network_thread)
+ : network_thread_(network_thread),
+ event_callback_(NULL) {
}
JingleHostConnection::~JingleHostConnection() {
@@ -19,12 +19,13 @@ JingleHostConnection::~JingleHostConnection() {
void JingleHostConnection::Connect(const std::string& username,
const std::string& password,
- const std::string& host_jid) {
+ const std::string& host_jid,
+ HostEventCallback* event_callback) {
message_loop()->PostTask(
FROM_HERE,
- NewRunnableMethod(this,
- &JingleHostConnection::DoConnect,
- username, password, host_jid));
+ NewRunnableMethod(this, &JingleHostConnection::DoConnect,
+ username, password, host_jid,
+ event_callback));
}
void JingleHostConnection::Disconnect() {
@@ -109,9 +110,12 @@ MessageLoop* JingleHostConnection::message_loop() {
void JingleHostConnection::DoConnect(const std::string& username,
const std::string& auth_token,
- const std::string& host_jid) {
+ const std::string& host_jid,
+ 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);
diff --git a/remoting/client/jingle_host_connection.h b/remoting/client/jingle_host_connection.h
index 00faaa1..96178aa 100644
--- a/remoting/client/jingle_host_connection.h
+++ b/remoting/client/jingle_host_connection.h
@@ -20,6 +20,7 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/task.h"
#include "remoting/base/protocol_decoder.h"
#include "remoting/client/host_connection.h"
#include "remoting/jingle_glue/jingle_channel.h"
@@ -31,19 +32,17 @@ namespace remoting {
class JingleThread;
-class JingleHostConnection :
- public base::RefCountedThreadSafe<JingleHostConnection>,
- public HostConnection,
- public JingleChannel::Callback,
- public JingleClient::Callback {
+class JingleHostConnection : public HostConnection,
+ public JingleChannel::Callback,
+ public JingleClient::Callback {
public:
- JingleHostConnection(JingleThread* network_thread,
- HostEventCallback* event_callback);
+ explicit JingleHostConnection(JingleThread* network_thread);
virtual ~JingleHostConnection();
virtual void Connect(const std::string& username,
const std::string& auth_token,
- const std::string& host_jid);
+ const std::string& host_jid,
+ HostEventCallback* event_callback);
virtual void Disconnect();
// JingleChannel::Callback interface.
@@ -64,7 +63,8 @@ class JingleHostConnection :
void DoConnect(const std::string& username,
const std::string& auth_token,
- const std::string& host_jid);
+ const std::string& host_jid,
+ HostEventCallback* event_callback);
void DoDisconnect();
JingleThread* network_thread_;
@@ -80,4 +80,6 @@ class JingleHostConnection :
} // namespace remoting
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::JingleHostConnection);
+
#endif // REMOTING_CLIENT_JINGLE_HOST_CONNECTION_H_
diff --git a/remoting/client/plugin/chromoting_main.cc b/remoting/client/plugin/chromoting_main.cc
index e2974bd..9d02936 100644
--- a/remoting/client/plugin/chromoting_main.cc
+++ b/remoting/client/plugin/chromoting_main.cc
@@ -8,7 +8,7 @@
// This information needs to live outside of the PepperPlugin since it can
// be requested by the browser before the PepperPlugin has been instantiated.
void InitializePluginInfo(pepper::PepperPlugin::Info* plugin_info) {
- plugin_info->mime_description = remoting::kMimeType;
+ plugin_info->mime_description = remoting::ChromotingPlugin::kMimeType;
plugin_info->plugin_name = "Chromoting";
plugin_info->plugin_description = "Remote access for Chrome";
}
diff --git a/remoting/client/plugin/chromoting_plugin.cc b/remoting/client/plugin/chromoting_plugin.cc
index 6ed867a..55c72afe 100644
--- a/remoting/client/plugin/chromoting_plugin.cc
+++ b/remoting/client/plugin/chromoting_plugin.cc
@@ -4,15 +4,28 @@
#include "remoting/client/plugin/chromoting_plugin.h"
-#include "remoting/client/plugin/client.h"
+#include <string>
+#include <vector>
+
+#include "base/string_util.h"
+#include "base/thread.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_view.h"
+#include "remoting/jingle_glue/jingle_thread.h"
+
+using std::string;
+using std::vector;
namespace remoting {
+const char* ChromotingPlugin::kMimeType =
+ "pepper-application/x-chromoting-plugin::Chromoting";
+
ChromotingPlugin::ChromotingPlugin(NPNetscapeFuncs* browser_funcs,
NPP instance)
: PepperPlugin(browser_funcs, instance) {
- device_ = extensions()->acquireDevice(instance, NPPepper2DDevice);
- client_ = new ChromotingClient(this);
}
ChromotingPlugin::~ChromotingPlugin() {
@@ -20,6 +33,8 @@ ChromotingPlugin::~ChromotingPlugin() {
NPError ChromotingPlugin::New(NPMIMEType pluginType,
int16 argc, char* argn[], char* argv[]) {
+ LOG(INFO) << "Started ChromotingPlugin::New";
+
// Verify the mime type and subtype
std::string mime(kMimeType);
std::string::size_type type_end = mime.find("/");
@@ -41,30 +56,60 @@ NPError ChromotingPlugin::New(NPMIMEType pluginType,
return NPERR_GENERIC_ERROR;
}
- return NPERR_NO_ERROR;
-}
+ string user_id;
+ string auth_token;
+ string host_jid;
+ if (!ParseUrl(url, &user_id, &auth_token, &host_jid)) {
+ LOG(WARNING) << "Could not parse URL: " << url;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // Setup pepper context.
+ device_ = extensions()->acquireDevice(instance(), NPPepper2DDevice);
+
+ // Start the threads.
+ main_thread_.reset(new base::Thread("ChromoClientMain"));
+ if (!main_thread_->Start()) {
+ LOG(ERROR) << "Main thread failed to start.";
+ return NPERR_GENERIC_ERROR;
+ }
+ network_thread_.reset(new JingleThread());
+ network_thread_->Start();
+
+ // Create the chromting objects.
+ host_connection_.reset(new JingleHostConnection(network_thread_.get()));
+ view_.reset(new PepperView(main_thread_->message_loop(), device_,
+ instance()));
+ client_.reset(new ChromotingClient(main_thread_->message_loop(),
+ host_connection_.get(), view_.get()));
+
+ // Kick off the connection.
+ host_connection_->Connect(user_id, auth_token, host_jid, client_.get());
-NPError ChromotingPlugin::Destroy(NPSavedData** save) {
return NPERR_NO_ERROR;
}
-void ChromotingPlugin::draw() {
- NPDeviceContext2D context;
- NPDeviceContext2DConfig config;
- device_->initializeContext(instance(), &config, &context);
+NPError ChromotingPlugin::Destroy(NPSavedData** save) {
+ host_connection_->Disconnect();
- client_->draw(width_, height_, &context);
+ // 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.
+ network_thread_->Stop();
+ main_thread_->Stop();
- device_->flushContext(instance(), &context, NULL, NULL);
+ main_thread_.reset();
+ network_thread_.reset();
+ return NPERR_NO_ERROR;
}
NPError ChromotingPlugin::SetWindow(NPWindow* window) {
width_ = window->width;
height_ = window->height;
- client_->set_window();
-
- draw();
+ client_->SetViewport(0, 0, window->width, window->height);
+ client_->Repaint();
return NPERR_NO_ERROR;
}
@@ -82,7 +127,7 @@ int16 ChromotingPlugin::HandleEvent(void* event) {
case NPEventType_MouseEnter:
// Fall through
case NPEventType_MouseLeave:
- client_->handle_mouse_event(npevent);
+ //client_->handle_mouse_event(npevent);
break;
case NPEventType_MouseWheel:
case NPEventType_RawKeyDown:
@@ -91,7 +136,7 @@ int16 ChromotingPlugin::HandleEvent(void* event) {
case NPEventType_KeyUp:
break;
case NPEventType_Char:
- client_->handle_char_event(npevent);
+ //client_->handle_char_event(npevent);
break;
case NPEventType_Minimize:
case NPEventType_Focus:
@@ -110,4 +155,41 @@ NPError ChromotingPlugin::SetValue(NPNVariable variable, void* value) {
return NPERR_NO_ERROR;
}
+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 e2bc78f..16e6f1d 100644
--- a/remoting/client/plugin/chromoting_plugin.h
+++ b/remoting/client/plugin/chromoting_plugin.h
@@ -7,43 +7,80 @@
#include <string>
+#include "base/at_exit.h"
+#include "base/scoped_ptr.h"
+#include "remoting/client/host_connection.h"
#include "remoting/client/pepper/pepper_plugin.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+namespace base {
+class Thread;
+} // namespace base
namespace remoting {
-static const char kMimeType[]
- = "pepper-application/x-chromoting-plugin::Chromoting";
+class ChromotingClient;
+class HostConnection;
+class JingleThread;
+class PepperView;
class ChromotingClient;
class ChromotingPlugin : public pepper::PepperPlugin {
public:
+ // The mimetype for which this plugin is registered.
+ //
+ // TODO(ajwong): Mimetype doesn't really make sense for us as the trigger
+ // point. I think we should handle a special protocol (eg., chromotocol://)
+ static const char *kMimeType;
+
ChromotingPlugin(NPNetscapeFuncs* browser_funcs, NPP instance);
virtual ~ChromotingPlugin();
- int width() { return width_; }
- int height() { return height_; }
- NPDevice* device() { return device_; }
+ // PepperPlugin implementation.
+ virtual NPError New(NPMIMEType pluginType, int16 argc, char* argn[],
+ char* argv[]);
+ virtual NPError Destroy(NPSavedData** save);
+ virtual NPError SetWindow(NPWindow* window);
+ virtual int16 HandleEvent(void* event);
+ virtual NPError GetValue(NPPVariable variable, void* value);
+ virtual NPError SetValue(NPNVariable variable, void* value);
- NPError New(NPMIMEType pluginType, int16 argc, char* argn[], char* argv[]);
- NPError Destroy(NPSavedData** save);
- NPError SetWindow(NPWindow* window);
- int16 HandleEvent(void* event);
- NPError GetValue(NPPVariable variable, void* value);
- NPError SetValue(NPNVariable variable, void* value);
+ private:
+ FRIEND_TEST(ChromotingPluginTest, ParseUrl);
+ FRIEND_TEST(ChromotingPluginTest, TestCaseSetup);
+
+ NPDevice* device() { return device_; }
- // Set up drawing context and update display.
- void draw();
+ static bool ParseUrl(const std::string& url,
+ std::string* user_id,
+ std::string* auth_token,
+ std::string* host_jid);
- private:
// Size of the plugin window.
int width_, height_;
// Rendering device provided by browser.
NPDevice* device_;
- // Chromoting client manager.
- ChromotingClient* client_;
+ // Since the ChromotingPlugin's lifetime is conceptually the lifetime of the
+ // object, use it to control running of atexit() calls.
+ //
+ // TODO(ajwong): Should this be moved into PepperPlugin? Or maybe even
+ // higher?
+ //
+ // TODO(ajwong): This causes unittests to fail so commenting out for now. We
+ // need to understand process instantiation better. This may also be a
+ // non-issue when we are no longer being loaded as a DSO.
+ //
+ // base::AtExitManager at_exit_manager_;
+
+ scoped_ptr<base::Thread> main_thread_;
+ scoped_ptr<JingleThread> network_thread_;
+
+ scoped_ptr<HostConnection> host_connection_;
+ scoped_ptr<PepperView> view_;
+ 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 12f9193..fedf252 100644
--- a/remoting/client/plugin/chromoting_plugin_unittest.cc
+++ b/remoting/client/plugin/chromoting_plugin_unittest.cc
@@ -13,6 +13,7 @@
pepper::PepperPlugin* CreatePlugin(NPNetscapeFuncs* browser_funcs,
NPP instance);
+namespace remoting {
class ChromotingPluginTest : public testing::Test {
protected:
@@ -24,10 +25,10 @@ class ChromotingPluginTest : public testing::Test {
instance_.reset(new NPP_t());
// Create the ChromotingPlugin for testing.
- pepper::PepperPlugin* pepper_plugin;
- pepper_plugin = CreatePlugin(browser_funcs_, instance_.get());
+ pepper::PepperPlugin* pepper_plugin =
+ CreatePlugin(browser_funcs_, instance_.get());
plugin_.reset(
- reinterpret_cast<remoting::ChromotingPlugin*>(pepper_plugin));
+ static_cast<ChromotingPlugin*>(pepper_plugin));
}
virtual void TearDown() {
@@ -35,48 +36,44 @@ class ChromotingPluginTest : public testing::Test {
FakeBrowser* fake_browser_;
scoped_ptr<NPP_t> instance_;
- scoped_ptr<remoting::ChromotingPlugin> plugin_;
+ scoped_ptr<ChromotingPlugin> plugin_;
};
-TEST_F(ChromotingPluginTest, TestSetup) {
+TEST_F(ChromotingPluginTest, TestCaseSetup) {
ASSERT_TRUE(plugin_->browser() != NULL);
ASSERT_TRUE(plugin_->extensions() != NULL);
ASSERT_TRUE(plugin_->instance() != NULL);
- ASSERT_TRUE(plugin_->device() != NULL);
+ // Device is not set until New() is called.
+ ASSERT_TRUE(plugin_->device() == NULL);
}
+#if 0
+TODO(ajwong): reenable once we have the threading sorted out.
TEST_F(ChromotingPluginTest, TestNew) {
NPMIMEType mimetype =
const_cast<NPMIMEType>("pepper-application/x-chromoting-plugin");
int16 argc;
char* argn[4];
char* argv[4];
- NPError result;
-
- // Test 0 arguments (NULL arrays).
- argc = 0;
- result = plugin_->New(mimetype, argc, NULL, NULL);
- ASSERT_EQ(NPERR_GENERIC_ERROR, result);
// Test 0 arguments.
argc = 0;
- result = plugin_->New(mimetype, argc, argn, argv);
- ASSERT_EQ(NPERR_GENERIC_ERROR, result);
+ ASSERT_EQ(NPERR_GENERIC_ERROR, plugin_->New(mimetype, argc, argn, argv));
// Test 1 argument (missing "src").
argc = 1;
argn[0] = const_cast<char*>("noturl");
argv[0] = const_cast<char*>("random.value");
- result = plugin_->New(mimetype, argc, argn, argv);
- ASSERT_EQ(NPERR_GENERIC_ERROR, result);
+ ASSERT_EQ(NPERR_GENERIC_ERROR, plugin_->New(mimetype, argc, argn, argv));
// Test "src" argument.
argc = 1;
argn[0] = const_cast<char*>("src");
- argv[0] = const_cast<char*>("chromotocol:name@chromoting.org");
- result = plugin_->New(mimetype, argc, argn, argv);
- ASSERT_EQ(NPERR_NO_ERROR, result);
+ argv[0] = const_cast<char*>("chromotocol://name?user=u&auth=a&jid=j");
+ ASSERT_EQ(NPERR_NO_ERROR, plugin_->New(mimetype, argc, argn, argv));
+
+ ASSERT_EQ(NPERR_NO_ERROR, plugin_->Destroy(NULL));
}
TEST_F(ChromotingPluginTest, TestSetWindow) {
@@ -86,3 +83,19 @@ TEST_F(ChromotingPluginTest, TestSetWindow) {
result = plugin_->SetWindow(window);
ASSERT_EQ(NPERR_NO_ERROR, result);
}
+#endif
+
+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_view.cc b/remoting/client/plugin/pepper_view.cc
new file mode 100644
index 0000000..d66624b5
--- /dev/null
+++ b/remoting/client/plugin/pepper_view.cc
@@ -0,0 +1,154 @@
+// 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_view.h"
+
+#include "base/message_loop.h"
+#include "remoting/client/decoder_verbatim.h"
+
+namespace remoting {
+
+PepperView::PepperView(MessageLoop* message_loop, NPDevice* rendering_device,
+ NPP plugin_instance)
+ : message_loop_(message_loop),
+ rendering_device_(rendering_device),
+ plugin_instance_(plugin_instance),
+ backing_store_width_(0),
+ backing_store_height_(0),
+ viewport_x_(0),
+ viewport_y_(0),
+ viewport_width_(0),
+ viewport_height_(0),
+ is_static_fill_(false),
+ static_fill_color_(0) {
+}
+
+PepperView::~PepperView() {
+}
+
+void PepperView::Paint() {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoPaint));
+}
+
+void PepperView::SetSolidFill(uint32 color) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoSetSolidFill, color));
+}
+
+void PepperView::UnsetSolidFill() {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoUnsetSolidFill));
+}
+
+void PepperView::SetViewport(int x, int y, int width, int height) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoSetViewport,
+ x, y, width, height));
+}
+
+void PepperView::SetBackingStoreSize(int width, int height) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoSetBackingStoreSize,
+ width, height));
+}
+
+void PepperView::HandleBeginUpdateStream(HostMessage* msg) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoHandleBeginUpdateStream, msg));
+}
+
+void PepperView::HandleUpdateStreamPacket(HostMessage* msg) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoHandleUpdateStreamPacket, msg));
+}
+
+void PepperView::HandleEndUpdateStream(HostMessage* msg) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperView::DoHandleEndUpdateStream, msg));
+}
+
+void PepperView::DoPaint() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ LOG(INFO) << "Starting PepperView::DoPaint";
+
+ NPDeviceContext2D context;
+ NPDeviceContext2DConfig config;
+ rendering_device_->initializeContext(plugin_instance_, &config, &context);
+
+ uint32* output_bitmap = static_cast<uint32*>(context.region);
+
+ // TODO(ajwong): Remove debugging code and actually hook up real painting
+ // logic from the decoder.
+ LOG(INFO) << "Painting top: " << context.dirty.top
+ << " bottom: " << context.dirty.bottom
+ << " left: " << context.dirty.left
+ << " right: " << context.dirty.right;
+ for (int i = context.dirty.top; i < context.dirty.bottom; ++i) {
+ for (int j = context.dirty.left; j < context.dirty.right; ++j) {
+ *output_bitmap++ = static_fill_color_;
+ }
+ }
+
+ rendering_device_->flushContext(plugin_instance_, &context, NULL, NULL);
+ LOG(INFO) << "Finishing PepperView::DoPaint";
+}
+
+void PepperView::DoSetSolidFill(uint32 color) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ is_static_fill_ = true;
+ static_fill_color_ = color;
+}
+
+void PepperView::DoUnsetSolidFill() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ is_static_fill_ = false;
+}
+
+void PepperView::DoSetViewport(int x, int y, int width, int height) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ viewport_x_ = x;
+ viewport_y_ = y;
+ viewport_width_ = width;
+ viewport_height_ = height;
+}
+
+void PepperView::DoSetBackingStoreSize(int width, int height) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ backing_store_width_ = width;
+ backing_store_height_ = height;
+}
+
+void PepperView::DoHandleBeginUpdateStream(HostMessage* msg) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ NOTIMPLEMENTED();
+}
+
+void PepperView::DoHandleUpdateStreamPacket(HostMessage* msg) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ NOTIMPLEMENTED();
+}
+
+void PepperView::DoHandleEndUpdateStream(HostMessage* msg) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ NOTIMPLEMENTED();
+}
+
+} // namespace remoting
diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h
new file mode 100644
index 0000000..286a15a
--- /dev/null
+++ b/remoting/client/plugin/pepper_view.h
@@ -0,0 +1,77 @@
+// 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_VIEW_H_
+#define REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "remoting/client/chromoting_view.h"
+#include "remoting/client/pepper/pepper_plugin.h"
+
+class MessageLoop;
+
+namespace remoting {
+
+class Decoder;
+
+class PepperView : public ChromotingView {
+ public:
+ // Constructs a PepperView that draw to the |rendering_device|. The
+ // |rendering_device| instance must outlive this class.
+ //
+ // TODO(ajwong): This probably needs to synchronize with the pepper thread
+ // to be safe.
+ PepperView(MessageLoop* message_loop, NPDevice* rendering_device,
+ NPP plugin_instance);
+ virtual ~PepperView();
+
+ // ChromotingView implementation.
+ 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 HandleBeginUpdateStream(HostMessage* msg);
+ virtual void HandleUpdateStreamPacket(HostMessage* msg);
+ virtual void HandleEndUpdateStream(HostMessage* msg);
+
+ private:
+ void DoPaint();
+ void DoSetSolidFill(uint32 color);
+ void DoUnsetSolidFill();
+ void DoSetViewport(int x, int y, int width, int height);
+ void DoSetBackingStoreSize(int width, int height);
+ void DoHandleBeginUpdateStream(HostMessage* msg);
+ void DoHandleUpdateStreamPacket(HostMessage* msg);
+ void DoHandleEndUpdateStream(HostMessage* msg);
+
+ // Synchronization and thread handling objects.
+ MessageLoop* message_loop_;
+
+ // Handles to Pepper objects needed for drawing to the screen.
+ NPDevice* rendering_device_;
+ NPP plugin_instance_;
+
+ int backing_store_width_;
+ int backing_store_height_;
+
+ int viewport_x_;
+ int viewport_y_;
+ int viewport_width_;
+ int viewport_height_;
+
+ bool is_static_fill_;
+ uint32 static_fill_color_;
+
+ scoped_ptr<Decoder> decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperView);
+};
+
+} // namespace remoting
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::PepperView);
+
+#endif // REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_
diff --git a/remoting/client/simple_client.cc b/remoting/client/simple_client.cc
index b2e9ce8..98074bf 100644
--- a/remoting/client/simple_client.cc
+++ b/remoting/client/simple_client.cc
@@ -129,14 +129,13 @@ int main(int argc, char** argv) {
base::WaitableEvent client_done(false, false);
SimpleHostEventCallback handler(network_thread.message_loop(), &client_done);
- scoped_refptr<JingleHostConnection> connection =
- new JingleHostConnection(&network_thread, &handler);
- connection->Connect(username, auth_token, host_jid);
+ 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();
+ connection.Disconnect();
network_thread.message_loop()->PostTask(FROM_HERE,
new MessageLoop::QuitTask());
network_thread.Stop();
diff --git a/remoting/client/x11_client.cc b/remoting/client/x11_client.cc
index 11b0ebf..4b111e9 100644
--- a/remoting/client/x11_client.cc
+++ b/remoting/client/x11_client.cc
@@ -28,8 +28,7 @@ using remoting::JingleThread;
namespace remoting {
-class X11Client : public base::RefCountedThreadSafe<X11Client>,
- public HostConnection::HostEventCallback {
+class X11Client : public HostConnection::HostEventCallback {
public:
X11Client(MessageLoop* loop, base::WaitableEvent* client_done)
: message_loop_(loop),
@@ -145,7 +144,7 @@ class X11Client : public base::RefCountedThreadSafe<X11Client>,
XResizeWindow(display_, window_, width_, height_);
// Now construct the X11View that renders the remote desktop.
- view_ = new X11View(display_, window_, width_, height_);
+ view_.reset(new X11View(display_, window_, width_, height_));
// Schedule the event handler to process the event queue of X11.
ScheduleX11EventHandler();
@@ -215,13 +214,15 @@ class X11Client : public base::RefCountedThreadSafe<X11Client>,
int width_;
int height_;
- scoped_refptr<ChromotingView> view_;
+ scoped_ptr<ChromotingView> view_;
DISALLOW_COPY_AND_ASSIGN(X11Client);
};
} // namespace remoting
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::X11Client);
+
int main(int argc, char** argv) {
base::AtExitManager at_exit;
std::string host_jid;
@@ -237,20 +238,18 @@ int main(int argc, char** argv) {
network_thread.Start();
base::WaitableEvent client_done(false, false);
- scoped_refptr<remoting::X11Client> client =
- new remoting::X11Client(network_thread.message_loop(), &client_done);
- scoped_refptr<JingleHostConnection> connection =
- new JingleHostConnection(&network_thread, client);
- connection->Connect(username, auth_token, host_jid);
+ remoting::X11Client client(network_thread.message_loop(), &client_done);
+ JingleHostConnection connection(&network_thread);
+ connection.Connect(username, auth_token, host_jid, &client);
- client->InitX11();
+ client.InitX11();
// Wait until the main loop is done.
client_done.Wait();
- connection->Disconnect();
+ connection.Disconnect();
- client->DestroyX11();
+ client.DestroyX11();
// Quit the current message loop.
network_thread.message_loop()->PostTask(FROM_HERE,
diff --git a/remoting/client/x11_view.cc b/remoting/client/x11_view.cc
index 599fa31..eb16acc 100644
--- a/remoting/client/x11_view.cc
+++ b/remoting/client/x11_view.cc
@@ -8,6 +8,8 @@
#include <X11/Xutil.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xcomposite.h>
+
+#include "base/logging.h"
#include "remoting/client/decoder_verbatim.h"
namespace remoting {
@@ -74,6 +76,26 @@ void X11View::Paint() {
XFreePixmap(display_, pixmap);
}
+void X11View::SetSolidFill(uint32 color) {
+ // TODO(ajwong): Implement.
+ NOTIMPLEMENTED();
+}
+
+void X11View::UnsetSolidFill() {
+ // TODO(ajwong): Implement.
+ NOTIMPLEMENTED();
+}
+
+void X11View::SetViewport(int x, int y, int width, int height) {
+ // TODO(ajwong): Implement.
+ NOTIMPLEMENTED();
+}
+
+void X11View::SetBackingStoreSize(int width, int height) {
+ // TODO(ajwong): Implement.
+ NOTIMPLEMENTED();
+}
+
void X11View::InitPaintTarget() {
// Testing XRender support.
int dummy;
diff --git a/remoting/client/x11_view.h b/remoting/client/x11_view.h
index f6f8a3d..1a76cb3 100644
--- a/remoting/client/x11_view.h
+++ b/remoting/client/x11_view.h
@@ -25,6 +25,10 @@ class X11View : public ChromotingView {
// ChromotingView implementations.
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 HandleBeginUpdateStream(HostMessage* msg);
virtual void HandleUpdateStreamPacket(HostMessage* msg);
virtual void HandleEndUpdateStream(HostMessage* msg) ;
@@ -54,4 +58,6 @@ class X11View : public ChromotingView {
} // namespace remoting
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::X11View);
+
#endif // REMOTING_CLIENT_X11_VIEW_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 101680f..9156951 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -26,19 +26,17 @@
'HAVE_STDINT_H', # Required by on2_integer.h
],
'dependencies': [
+ 'chromoting_base',
+ 'chromoting_client',
+ 'chromoting_jingle_glue',
'../third_party/zlib/zlib.gyp:zlib',
],
'sources': [
'client/plugin/chromoting_main.cc',
'client/plugin/chromoting_plugin.cc',
'client/plugin/chromoting_plugin.h',
- 'client/plugin/client.cc',
- 'client/plugin/client.h',
- 'client/plugin/compression.cc',
- 'client/plugin/compression.h',
- 'client/plugin/decoder.h',
- 'client/plugin/host_connection.cc',
- 'client/plugin/host_connection.h',
+ 'client/plugin/pepper_view.cc',
+ 'client/plugin/pepper_view.h',
'client/pepper/pepper_plugin.cc',
'client/pepper/pepper_plugin.h',
'../media/base/yuv_convert.cc',
@@ -60,28 +58,29 @@
], # end of 'conditions'
}, # end of target 'chromoting_client_plugin_lib'
+# TODO(ajwong): reenable once we figure out the -fPIC issues.
# Client plugin: libchromoting_plugin.so.
- {
- 'target_name': 'chromoting_client_plugin',
- 'type': 'shared_library',
- 'product_name': 'chromoting_plugin',
- 'dependencies': [
- 'chromoting_client_plugin_lib',
- ],
- 'sources': [
- # Required here (rather than in lib) so that functions are
- # exported properly.
- 'client/pepper/pepper_main.cc',
- ],
- 'conditions': [
- ['OS=="linux" and target_arch=="x64" and linux_fpic!=1', {
- # Shared libraries need -fPIC on x86-64
- 'cflags': [
- '-fPIC'
- ],
- }],
- ], # end of 'conditions'
- }, # end of target 'chromoting_client_plugin'
+# {
+# 'target_name': 'chromoting_client_plugin',
+# 'type': 'shared_library',
+# 'product_name': 'chromoting_plugin',
+# 'dependencies': [
+# 'chromoting_client_plugin_lib',
+# ],
+# 'sources': [
+# # Required here (rather than in lib) so that functions are
+# # exported properly.
+# 'client/pepper/pepper_main.cc',
+# ],
+# 'conditions': [
+# ['OS=="linux" and target_arch=="x64" and linux_fpic!=1', {
+# # Shared libraries need -fPIC on x86-64
+# 'cflags': [
+# '-fPIC'
+# ],
+# }],
+# ], # end of 'conditions'
+# }, # end of target 'chromoting_client_plugin'
# Simple webserver for testing chromoting client plugin.
{
@@ -226,9 +225,11 @@
'chromoting_jingle_glue',
],
'sources': [
+ 'client/chromoting_client.cc',
+ 'client/chromoting_client.h',
+ 'client/chromoting_view.h',
'client/client_util.cc',
'client/client_util.h',
- 'client/chromoting_view.h',
'client/decoder.h',
'client/decoder_verbatim.cc',
'client/decoder_verbatim.h',
diff --git a/remoting/tools/client_webserver/main.c b/remoting/tools/client_webserver/main.c
index 6f7baba..f9494b4 100644
--- a/remoting/tools/client_webserver/main.c
+++ b/remoting/tools/client_webserver/main.c
@@ -106,7 +106,10 @@ void handle_request(int connection) {
// However, we return empty content, but with the requested plugin mimetype.
write_data(connection, "HTTP/1.0 200 OK\r\n");
write_data(connection, "Content-Type: ");
- write_data(connection, mime_type);
+ // TODO(ajwong): Currently hardcoding the mimetype rather than parsing out of
+ // URL to make it easier to invoke the plugin. Change this back to writing
+ // |mime_type| out after we get things cleaned up.
+ write_data(connection, "pepper-application/x-chromoting-plugin");
write_data(connection, "\r\n\r\n");
// This dummy data is unused, but must be present or else the reader may hang.