1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/host/host_window_proxy.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/single_thread_task_runner.h"
11#include "remoting/host/client_session_control.h"
12#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
13
14namespace remoting {
15
16// Runs an instance of |HostWindow| on the |ui_task_runner_| thread.
17class HostWindowProxy::Core
18    : public base::RefCountedThreadSafe<Core>,
19      public ClientSessionControl {
20 public:
21  Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
22       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
23       scoped_ptr<HostWindow> host_window);
24
25  // Starts |host_window_| on the |ui_task_runner_| thread.
26  void Start(const base::WeakPtr<ClientSessionControl>& client_session_control);
27
28  // Destroys |host_window_| on the |ui_task_runner_| thread.
29  void Stop();
30
31 private:
32  friend class base::RefCountedThreadSafe<Core>;
33  virtual ~Core();
34
35  // Start() and Stop() equivalents called on the |ui_task_runner_| thread.
36  void StartOnUiThread(const std::string& client_jid);
37  void StopOnUiThread();
38
39  // ClientSessionControl interface.
40  virtual const std::string& client_jid() const OVERRIDE;
41  virtual void DisconnectSession() OVERRIDE;
42  virtual void OnLocalMouseMoved(
43      const webrtc::DesktopVector& position) OVERRIDE;
44  virtual void SetDisableInputs(bool disable_inputs) OVERRIDE;
45
46  // Task runner on which public methods of this class must be called.
47  scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
48
49  // Task runner on which |host_window_| is running.
50  scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
51
52  // Stores the client's JID so it can be read on the |ui_task_runner_| thread.
53  std::string client_jid_;
54
55  // Used to notify the caller about the local user's actions on
56  // the |caller_task_runner| thread.
57  base::WeakPtr<ClientSessionControl> client_session_control_;
58
59  // The wrapped |HostWindow| instance running on the |ui_task_runner_| thread.
60  scoped_ptr<HostWindow> host_window_;
61
62  // Used to create the control pointer passed to |host_window_|.
63  base::WeakPtrFactory<ClientSessionControl> weak_factory_;
64
65  DISALLOW_COPY_AND_ASSIGN(Core);
66};
67
68HostWindowProxy::HostWindowProxy(
69    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
70    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
71    scoped_ptr<HostWindow> host_window) {
72  DCHECK(caller_task_runner->BelongsToCurrentThread());
73
74  // Detach |host_window| from the calling thread so that |Core| could run it on
75  // the |ui_task_runner_| thread.
76  host_window->DetachFromThread();
77  core_ = new Core(caller_task_runner, ui_task_runner, host_window.Pass());
78}
79
80HostWindowProxy::~HostWindowProxy() {
81  DCHECK(CalledOnValidThread());
82
83  core_->Stop();
84}
85
86void HostWindowProxy::Start(
87    const base::WeakPtr<ClientSessionControl>& client_session_control) {
88  DCHECK(CalledOnValidThread());
89
90  core_->Start(client_session_control);
91}
92
93HostWindowProxy::Core::Core(
94    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
95    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
96    scoped_ptr<HostWindow> host_window)
97    : caller_task_runner_(caller_task_runner),
98      ui_task_runner_(ui_task_runner),
99      host_window_(host_window.Pass()),
100      weak_factory_(this) {
101  DCHECK(caller_task_runner->BelongsToCurrentThread());
102}
103
104void HostWindowProxy::Core::Start(
105    const base::WeakPtr<ClientSessionControl>& client_session_control) {
106  DCHECK(caller_task_runner_->BelongsToCurrentThread());
107  DCHECK(!client_session_control_.get());
108  DCHECK(client_session_control.get());
109
110  client_session_control_ = client_session_control;
111  ui_task_runner_->PostTask(
112      FROM_HERE, base::Bind(&Core::StartOnUiThread, this,
113                            client_session_control->client_jid()));
114}
115
116void HostWindowProxy::Core::Stop() {
117  DCHECK(caller_task_runner_->BelongsToCurrentThread());
118
119  ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::StopOnUiThread, this));
120}
121
122HostWindowProxy::Core::~Core() {
123  DCHECK(!host_window_);
124}
125
126void HostWindowProxy::Core::StartOnUiThread(const std::string& client_jid) {
127  DCHECK(ui_task_runner_->BelongsToCurrentThread());
128  DCHECK(client_jid_.empty());
129
130  client_jid_ = client_jid;
131  host_window_->Start(weak_factory_.GetWeakPtr());
132}
133
134void HostWindowProxy::Core::StopOnUiThread() {
135  DCHECK(ui_task_runner_->BelongsToCurrentThread());
136
137  host_window_.reset();
138}
139
140const std::string& HostWindowProxy::Core::client_jid() const {
141  DCHECK(ui_task_runner_->BelongsToCurrentThread());
142
143  return client_jid_;
144}
145
146void HostWindowProxy::Core::DisconnectSession() {
147  if (!caller_task_runner_->BelongsToCurrentThread()) {
148    caller_task_runner_->PostTask(FROM_HERE,
149                                  base::Bind(&Core::DisconnectSession, this));
150    return;
151  }
152
153  if (client_session_control_.get())
154    client_session_control_->DisconnectSession();
155}
156
157void HostWindowProxy::Core::OnLocalMouseMoved(
158    const webrtc::DesktopVector& position) {
159  if (!caller_task_runner_->BelongsToCurrentThread()) {
160    caller_task_runner_->PostTask(
161        FROM_HERE, base::Bind(&Core::OnLocalMouseMoved, this, position));
162    return;
163  }
164
165  if (client_session_control_.get())
166    client_session_control_->OnLocalMouseMoved(position);
167}
168
169void HostWindowProxy::Core::SetDisableInputs(bool disable_inputs) {
170  if (!caller_task_runner_->BelongsToCurrentThread()) {
171    caller_task_runner_->PostTask(
172        FROM_HERE, base::Bind(&Core::SetDisableInputs, this, disable_inputs));
173    return;
174  }
175
176  if (client_session_control_.get())
177    client_session_control_->SetDisableInputs(disable_inputs);
178}
179
180}  // namespace remoting
181