Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: components/exo/gamepad.cc

Issue 2076013002: exo: Implement wayland gamepad support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@serv
Patch Set: moved polling thread resources into separate class. pass task_runner into Gamepad. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "components/exo/gamepad.h"
6
7 #include <cmath>
8
9 #include "ash/shell.h"
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "components/exo/gamepad_delegate.h"
16 #include "components/exo/shell_surface.h"
17 #include "components/exo/surface.h"
18 #include "device/gamepad/gamepad_data_fetcher.h"
19 #include "device/gamepad/gamepad_platform_data_fetcher.h"
20 #include "ui/aura/client/focus_client.h"
21 #include "ui/aura/window.h"
22
23 namespace exo {
24 namespace {
25
26 constexpr double kGamepadButtonValueEpsilon = 0.001;
27 bool GamepadButtonValuesAreEqual(double a, double b) {
28 return fabs(a - b) < kGamepadButtonValueEpsilon;
29 }
30
31 // Time between gamepad polls in milliseconds.
32 constexpr unsigned kPollingTimeIntervalMs = 16;
33
34 } // namespace
35
36 ////////////////////////////////////////////////////////////////////////////////
37 // Gamepad::PollingThreadResources
38
39 // Implements all methods and resources running on the polling thread.
40 // This class is reference counted to allow it to shut down safely on the
41 // polling thread even if the Gamepad has been destroyed on the origin thread.
42 class Gamepad::PollingThreadResources
reveman 2016/07/11 10:50:44 nit: this class contains more than some resources.
denniskempin 2016/07/11 17:43:28 Done.
43 : public base::RefCounted<Gamepad::PollingThreadResources> {
reveman 2016/07/11 10:50:44 Does this need to be base::ThreadSafeRefCounted?
denniskempin 2016/07/11 17:43:28 Done.
44 public:
45 typedef base::Callback<void(const blink::WebGamepad)>
46 PostGamepadChangesCallback;
reveman 2016/07/11 10:50:44 nit: using HandleGamepadChangesCallback = ..
denniskempin 2016/07/11 17:43:28 Done.
47
48 PollingThreadResources(
49 const PostGamepadChangesCallback& post_gamepad_changes,
50 const GamepadDataFetcherFactory& fetcher_factory,
51 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
reveman 2016/07/11 10:50:44 nit: different parts of chrome does this different
denniskempin 2016/07/11 17:43:28 Done.
52 : post_gamepad_changes_(post_gamepad_changes),
53 fetcher_factory_(fetcher_factory),
54 polling_task_runner_(task_runner),
55 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
56 thread_checker_.DetachFromThread();
57 }
58
59 // Enable or disable gamepad polling. Can be called from any thread.
60 void EnablePolling(bool enabled) {
61 polling_task_runner_->PostTask(
62 FROM_HERE,
63 base::Bind(&PollingThreadResources::EnablePollingOnPollingThread,
64 make_scoped_refptr(this), enabled));
65 }
66
67 private:
68 friend class base::RefCounted<PollingThreadResources>;
69 virtual ~PollingThreadResources() {}
reveman 2016/07/11 10:50:44 nit: blank line before this
denniskempin 2016/07/11 17:43:28 Done.
70
71 // Enables or disables polling.
72 void EnablePollingOnPollingThread(bool enabled) {
73 DCHECK(thread_checker_.CalledOnValidThread());
74
75 if (enabled == is_enabled_)
reveman 2016/07/11 10:50:44 nit: is this check needed?
denniskempin 2016/07/11 17:43:28 Done.
76 return;
77 is_enabled_ = enabled;
78
79 if (is_enabled_)
80 SchedulePollOnPollingThread();
81 }
82
83 // Schedules the next poll on the polling thread.
84 void SchedulePollOnPollingThread() {
85 DCHECK(thread_checker_.CalledOnValidThread());
86 if (!is_enabled_) {
reveman 2016/07/11 10:50:44 is this needed? if it is, then shouldn't the condi
denniskempin 2016/07/11 17:43:28 Done. I've moved the creation/destruction of the f
87 fetcher_.reset();
88 return;
89 }
90
91 if (has_poll_scheduled_)
92 return;
93
94 if (!fetcher_) {
95 fetcher_ = fetcher_factory_.Run();
96 DCHECK(fetcher_);
97 }
98
99 has_poll_scheduled_ = true;
100 polling_task_runner_->PostDelayedTask(
101 FROM_HERE, base::Bind(&PollingThreadResources::PollOnPollingThread,
102 make_scoped_refptr(this)),
103 base::TimeDelta::FromMilliseconds(kPollingTimeIntervalMs));
104 }
105
106 // Polls devices for new data and posts gamepad changes back to origin thread.
107 void PollOnPollingThread() {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 DCHECK(fetcher_);
110 blink::WebGamepads new_state = state_;
111
reveman 2016/07/11 10:50:44 nit: move this blank line above l.110 instead
denniskempin 2016/07/11 17:43:28 Done.
112 fetcher_->GetGamepadData(&new_state, false);
113
114 if (std::max(new_state.length, state_.length) > 0) {
115 if (new_state.items[0].connected != state_.items[0].connected ||
116 new_state.items[0].timestamp > state_.items[0].timestamp) {
117 origin_task_runner_->PostTask(
118 FROM_HERE, base::Bind(post_gamepad_changes_, new_state.items[0]));
119 }
120 }
121
122 state_ = new_state;
123 has_poll_scheduled_ = false;
124 SchedulePollOnPollingThread();
125 }
126
127 // Callback to PostGamepadChanges using weak reference to Gamepad.
128 PostGamepadChangesCallback post_gamepad_changes_;
129
130 // Factory method to create a gamepad data fetcher. Defaults to creating
131 // a PlatformGamepadDataFetcher instance, but can be overwritten for
132 // testing purposes.
133 GamepadDataFetcherFactory fetcher_factory_;
reveman 2016/07/11 10:50:44 nit: create_fetcher_callback_
denniskempin 2016/07/11 17:43:28 Done.
134
135 // Reference to task runner on polling thread.
136 scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner_;
137
138 // Reference to task runner on polling thread.
139 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
140
141 // Gamepad data fetcher used for querying gamepad devices.
142 std::unique_ptr<device::GamepadDataFetcher> fetcher_;
143
144 // The current state of all gamepads.
145 blink::WebGamepads state_;
146
147 // True if a poll has been scheduled.
148 bool has_poll_scheduled_{false};
reveman 2016/07/11 10:50:44 nit: "has_poll_scheduled_ = false" is preferred in
denniskempin 2016/07/11 17:43:28 Done.
149
150 // True if the polling thread is paused.
151 bool is_enabled_{true};
reveman 2016/07/11 10:50:44 nit: is_enabled_ = true
denniskempin 2016/07/11 17:43:28 Done.
152
153 // ThreadChecker for the polling thread.
154 base::ThreadChecker thread_checker_;
155
156 DISALLOW_COPY_AND_ASSIGN(PollingThreadResources);
157 };
158
159 ////////////////////////////////////////////////////////////////////////////////
160 // Gamepad, public:
161
162 Gamepad::Gamepad(
163 GamepadDelegate* delegate,
164 scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner)
165 : Gamepad(delegate,
166 polling_task_runner,
167 base::Bind(Gamepad::GamepadPlatformDataFetcherFactory)) {}
168
169 Gamepad::Gamepad(
170 GamepadDelegate* delegate,
171 scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner,
172 GamepadDataFetcherFactory fetcher_factory)
173 : delegate_(delegate), weak_factory_(this) {
174 polling_thread_resources_ = new PollingThreadResources(
175 base::Bind(&Gamepad::PostGamepadChanges, weak_factory_.GetWeakPtr()),
176 fetcher_factory, polling_task_runner);
177
178 aura::client::FocusClient* focus_client =
179 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
180 focus_client->AddObserver(this);
181 OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
182 }
183
184 Gamepad::~Gamepad() {
185 // Disable polling. Since PollingThreadResources are reference counted, we
186 // can safely have it shut down after Gamepad has been destroyed.
187 polling_thread_resources_->EnablePolling(false);
188
189 delegate_->OnGamepadDestroying(this);
190 aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
191 ->RemoveObserver(this);
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////
195 // aura::client::FocusChangeObserver overrides:
196
197 void Gamepad::OnWindowFocused(aura::Window* gained_focus,
198 aura::Window* lost_focus) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 Surface* target = nullptr;
201 if (gained_focus) {
202 target = Surface::AsSurface(gained_focus);
203 if (!target) {
204 aura::Window* top_level_window = gained_focus->GetToplevelWindow();
205 if (top_level_window)
206 target = ShellSurface::GetMainSurface(top_level_window);
207 }
208 }
209
210 bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
211 if (focused) {
reveman 2016/07/11 10:50:44 nit: polling_thread_resources_->EnablePolling(focu
denniskempin 2016/07/11 17:43:28 Done. Yes.. well this was just dumb ;)
212 polling_thread_resources_->EnablePolling(true);
213 } else {
214 polling_thread_resources_->EnablePolling(false);
215 }
216 }
217
218 ////////////////////////////////////////////////////////////////////////////////
219 // Gamepad, private:
220
221 void Gamepad::PostGamepadChanges(const blink::WebGamepad new_pad) {
222 DCHECK(thread_checker_.CalledOnValidThread());
223 bool send_frame = false;
224
225 // Update connection state.
226 if (new_pad.connected != pad_state_.connected) {
227 delegate_->OnStateChange(new_pad.connected);
228 }
229
230 if (!new_pad.connected || new_pad.timestamp <= pad_state_.timestamp) {
231 pad_state_ = new_pad;
232 return;
233 }
234
235 // Notify delegate of updated axes.
236 for (size_t axis = 0;
237 axis < std::max(pad_state_.axesLength, new_pad.axesLength); ++axis) {
238 if (!GamepadButtonValuesAreEqual(new_pad.axes[axis],
239 pad_state_.axes[axis])) {
240 send_frame = true;
241 delegate_->OnAxis(axis, new_pad.axes[axis]);
242 }
243 }
244
245 // Notify delegate of updated buttons.
246 for (size_t button_id = 0;
247 button_id < std::max(pad_state_.buttonsLength, new_pad.buttonsLength);
248 ++button_id) {
249 auto button = pad_state_.buttons[button_id];
250 auto new_button = new_pad.buttons[button_id];
251 if (button.pressed != new_button.pressed ||
252 !GamepadButtonValuesAreEqual(button.value, new_button.value)) {
253 send_frame = true;
254 delegate_->OnButton(button_id, new_button.pressed, new_button.value);
255 }
256 }
257 if (send_frame)
258 delegate_->OnFrame();
259
260 pad_state_ = new_pad;
261 }
262
263 std::unique_ptr<device::GamepadDataFetcher>
264 Gamepad::GamepadPlatformDataFetcherFactory() {
265 return std::unique_ptr<device::GamepadDataFetcher>(
266 new device::GamepadPlatformDataFetcher());
267 }
268
269 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698