[GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
[WebKit-https.git] / Source / WebKit / UIProcess / Gamepad / UIGamepadProvider.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "UIGamepadProvider.h"
28
29 #if ENABLE(GAMEPAD)
30
31 #include "GamepadData.h"
32 #include "UIGamepad.h"
33 #include "WebPageProxy.h"
34 #include "WebProcessPool.h"
35 #include <WebCore/MockGamepadProvider.h>
36 #include <WebCore/PlatformGamepad.h>
37 #include <wtf/NeverDestroyed.h>
38
39 namespace WebKit {
40 using namespace WebCore;
41
42 static const Seconds maximumGamepadUpdateInterval { 1_s / 120. };
43
44 UIGamepadProvider& UIGamepadProvider::singleton()
45 {
46     static NeverDestroyed<UIGamepadProvider> sharedProvider;
47     return sharedProvider;
48 }
49
50 UIGamepadProvider::UIGamepadProvider()
51     : m_gamepadSyncTimer(RunLoop::main(), this, &UIGamepadProvider::gamepadSyncTimerFired)
52 {
53     platformSetDefaultGamepadProvider();
54 }
55
56 UIGamepadProvider::~UIGamepadProvider()
57 {
58     if (!m_processPoolsUsingGamepads.isEmpty())
59         GamepadProvider::singleton().stopMonitoringGamepads(*this);
60 }
61
62 void UIGamepadProvider::gamepadSyncTimerFired()
63 {
64     auto webPageProxy = platformWebPageProxyForGamepadInput();
65     if (!webPageProxy || !m_processPoolsUsingGamepads.contains(&webPageProxy->process().processPool()))
66         return;
67
68     webPageProxy->gamepadActivity(snapshotGamepads(), m_shouldMakeGamepadsVisibleOnSync);
69     m_shouldMakeGamepadsVisibleOnSync = false;
70 }
71
72 void UIGamepadProvider::scheduleGamepadStateSync()
73 {
74     if (!m_isMonitoringGamepads || m_gamepadSyncTimer.isActive())
75         return;
76
77     if (m_gamepads.isEmpty() || m_processPoolsUsingGamepads.isEmpty()) {
78         m_gamepadSyncTimer.stop();
79         return;
80     }
81
82     m_gamepadSyncTimer.startOneShot(maximumGamepadUpdateInterval);
83 }
84
85 void UIGamepadProvider::setInitialConnectedGamepads(const Vector<PlatformGamepad*>& initialGamepads)
86 {
87     ASSERT(!m_hasInitialGamepads);
88
89     m_gamepads.resize(initialGamepads.size());
90
91     for (auto* gamepad : initialGamepads) {
92         if (!gamepad)
93             continue;
94         m_gamepads[gamepad->index()] = makeUnique<UIGamepad>(*gamepad);
95     }
96
97     for (auto& pool : m_processPoolsUsingGamepads)
98         pool->setInitialConnectedGamepads(m_gamepads);
99
100     m_hasInitialGamepads = true;
101 }
102
103 void UIGamepadProvider::platformGamepadConnected(PlatformGamepad& gamepad)
104 {
105     if (m_gamepads.size() <= gamepad.index())
106         m_gamepads.grow(gamepad.index() + 1);
107
108     ASSERT(!m_gamepads[gamepad.index()]);
109     m_gamepads[gamepad.index()] = makeUnique<UIGamepad>(gamepad);
110
111     scheduleGamepadStateSync();
112
113     for (auto& pool : m_processPoolsUsingGamepads)
114         pool->gamepadConnected(*m_gamepads[gamepad.index()]);
115 }
116
117 void UIGamepadProvider::platformGamepadDisconnected(PlatformGamepad& gamepad)
118 {
119     ASSERT(gamepad.index() < m_gamepads.size());
120     ASSERT(m_gamepads[gamepad.index()]);
121
122     std::unique_ptr<UIGamepad> disconnectedGamepad = WTFMove(m_gamepads[gamepad.index()]);
123
124     scheduleGamepadStateSync();
125
126     for (auto& pool : m_processPoolsUsingGamepads)
127         pool->gamepadDisconnected(*disconnectedGamepad);
128 }
129
130 void UIGamepadProvider::platformGamepadInputActivity(bool shouldMakeGamepadsVisible)
131 {
132     auto platformGamepads = GamepadProvider::singleton().platformGamepads();
133     ASSERT(platformGamepads.size() == m_gamepads.size());
134
135     for (size_t i = 0; i < platformGamepads.size(); ++i) {
136         if (!platformGamepads[i]) {
137             ASSERT(!m_gamepads[i]);
138             continue;
139         }
140
141         ASSERT(m_gamepads[i]);
142         m_gamepads[i]->updateFromPlatformGamepad(*platformGamepads[i]);
143     }
144
145     if (shouldMakeGamepadsVisible)
146         m_shouldMakeGamepadsVisibleOnSync = true;
147
148     scheduleGamepadStateSync();
149 }
150
151 void UIGamepadProvider::processPoolStartedUsingGamepads(WebProcessPool& pool)
152 {
153     ASSERT(!m_processPoolsUsingGamepads.contains(&pool));
154     m_processPoolsUsingGamepads.add(&pool);
155
156     if (!m_isMonitoringGamepads && platformWebPageProxyForGamepadInput())
157         startMonitoringGamepads();
158 }
159
160 void UIGamepadProvider::processPoolStoppedUsingGamepads(WebProcessPool& pool)
161 {
162     ASSERT(m_processPoolsUsingGamepads.contains(&pool));
163     m_processPoolsUsingGamepads.remove(&pool);
164
165     if (m_isMonitoringGamepads && !platformWebPageProxyForGamepadInput())
166         platformStopMonitoringInput();
167 }
168
169 void UIGamepadProvider::viewBecameActive(WebPageProxy& page)
170 {
171     if (!m_processPoolsUsingGamepads.contains(&page.process().processPool()))
172         return;
173
174     if (!m_isMonitoringGamepads)
175         startMonitoringGamepads();
176
177     if (platformWebPageProxyForGamepadInput())
178         platformStartMonitoringInput();
179 }
180
181 void UIGamepadProvider::viewBecameInactive(WebPageProxy& page)
182 {
183     auto pageForGamepadInput = platformWebPageProxyForGamepadInput();
184     if (pageForGamepadInput == &page)
185         platformStopMonitoringInput();
186 }
187
188 void UIGamepadProvider::startMonitoringGamepads()
189 {
190     if (m_isMonitoringGamepads)
191         return;
192
193     m_isMonitoringGamepads = true;
194     ASSERT(!m_processPoolsUsingGamepads.isEmpty());
195     GamepadProvider::singleton().startMonitoringGamepads(*this);
196 }
197
198 void UIGamepadProvider::stopMonitoringGamepads()
199 {
200     if (!m_isMonitoringGamepads)
201         return;
202
203     m_isMonitoringGamepads = false;
204
205     ASSERT(m_processPoolsUsingGamepads.isEmpty());
206     GamepadProvider::singleton().stopMonitoringGamepads(*this);
207
208     m_gamepads.clear();
209 }
210
211 Vector<GamepadData> UIGamepadProvider::snapshotGamepads()
212 {
213     Vector<GamepadData> gamepadDatas;
214     gamepadDatas.reserveInitialCapacity(m_gamepads.size());
215
216     for (auto& gamepad : m_gamepads) {
217         if (gamepad)
218             gamepadDatas.uncheckedAppend(gamepad->condensedGamepadData());
219         else
220             gamepadDatas.uncheckedAppend({ });
221     }
222
223     return gamepadDatas;
224 }
225
226 #if !PLATFORM(COCOA) && !USE(MANETTE)
227
228 void UIGamepadProvider::platformSetDefaultGamepadProvider()
229 {
230     // FIXME: Implement for other platforms
231 }
232
233 WebPageProxy* UIGamepadProvider::platformWebPageProxyForGamepadInput()
234 {
235     // FIXME: Implement for other platforms
236     return nullptr;
237 }
238
239 void UIGamepadProvider::platformStopMonitoringInput()
240 {
241 }
242
243 void UIGamepadProvider::platformStartMonitoringInput()
244 {
245 }
246
247 #endif // !PLATFORM(COCOA) && !USE(MANETTE)
248
249 }
250
251 #endif // ENABLE(GAMEPAD)