Title: [170549] trunk/Source/WebCore
Revision
170549
Author
[email protected]
Date
2014-06-27 13:35:55 -0700 (Fri, 27 Jun 2014)

Log Message

HIDGamepadProvider should only be active when someone is interested in Gamepads.
https://bugs.webkit.org/show_bug.cgi?id=134374

Reviewed by Darin Adler.

No new tests (Not yet a tested config)

* Modules/gamepad/GamepadManager.cpp:
(WebCore::GamepadManager::registerNavigator): Add some logging.
(WebCore::GamepadManager::unregisterNavigator): Ditto.

* platform/mac/HIDGamepadProvider.cpp:
(WebCore::HIDGamepadProvider::HIDGamepadProvider):
(WebCore::HIDGamepadProvider::connectionDelayTimerFired): Stop suppressing connection callbacks
(WebCore::HIDGamepadProvider::openAndScheduleManager):
(WebCore::HIDGamepadProvider::closeAndUnscheduleManager): Stop listening for gamepad events, and clear
  all current gamepads.
(WebCore::HIDGamepadProvider::startMonitoringGamepads): If the first client, call openAndScheduleManager
(WebCore::HIDGamepadProvider::stopMonitoringGamepads): If the last client, call closeAndUnscheduleManager
(WebCore::HIDGamepadProvider::deviceAdded): If this callback came while we were suppressing connection
  callbacks, it is a startup event for already-connected gamepads. Stop suppressing callbacks in a later
  spin of the runloop.
(WebCore::HIDGamepadProvider::deviceRemoved):
* platform/mac/HIDGamepadProvider.h:
(WebCore::HIDGamepadProvider::setShouldDispatchCallbacks): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (170548 => 170549)


--- trunk/Source/WebCore/ChangeLog	2014-06-27 20:31:31 UTC (rev 170548)
+++ trunk/Source/WebCore/ChangeLog	2014-06-27 20:35:55 UTC (rev 170549)
@@ -1,3 +1,31 @@
+2014-06-26  Brady Eidson  <[email protected]>
+
+        HIDGamepadProvider should only be active when someone is interested in Gamepads.
+        https://bugs.webkit.org/show_bug.cgi?id=134374
+
+        Reviewed by Darin Adler.
+
+        No new tests (Not yet a tested config)
+
+        * Modules/gamepad/GamepadManager.cpp:
+        (WebCore::GamepadManager::registerNavigator): Add some logging.
+        (WebCore::GamepadManager::unregisterNavigator): Ditto.
+
+        * platform/mac/HIDGamepadProvider.cpp:
+        (WebCore::HIDGamepadProvider::HIDGamepadProvider):
+        (WebCore::HIDGamepadProvider::connectionDelayTimerFired): Stop suppressing connection callbacks
+        (WebCore::HIDGamepadProvider::openAndScheduleManager):
+        (WebCore::HIDGamepadProvider::closeAndUnscheduleManager): Stop listening for gamepad events, and clear
+          all current gamepads.
+        (WebCore::HIDGamepadProvider::startMonitoringGamepads): If the first client, call openAndScheduleManager
+        (WebCore::HIDGamepadProvider::stopMonitoringGamepads): If the last client, call closeAndUnscheduleManager
+        (WebCore::HIDGamepadProvider::deviceAdded): If this callback came while we were suppressing connection
+          callbacks, it is a startup event for already-connected gamepads. Stop suppressing callbacks in a later
+          spin of the runloop.
+        (WebCore::HIDGamepadProvider::deviceRemoved):
+        * platform/mac/HIDGamepadProvider.h:
+        (WebCore::HIDGamepadProvider::setShouldDispatchCallbacks): Deleted.
+
 2014-06-27  Alex Christensen  <[email protected]>
 
         Prevent unnecessary register saving in css jit.

Modified: trunk/Source/WebCore/Modules/gamepad/GamepadManager.cpp (170548 => 170549)


--- trunk/Source/WebCore/Modules/gamepad/GamepadManager.cpp	2014-06-27 20:31:31 UTC (rev 170548)
+++ trunk/Source/WebCore/Modules/gamepad/GamepadManager.cpp	2014-06-27 20:35:55 UTC (rev 170549)
@@ -29,6 +29,7 @@
 
 #include "Gamepad.h"
 #include "GamepadProvider.h"
+#include "Logging.h"
 #include "NavigatorGamepad.h"
 #include "PlatformGamepad.h"
 
@@ -63,26 +64,34 @@
 
 void GamepadManager::registerNavigator(NavigatorGamepad* navigator)
 {
+    LOG(Gamepad, "GamepadManager registering NavigatorGamepad %p", navigator);
+
     ASSERT(!m_navigators.contains(navigator));
     m_navigators.add(navigator);
 
     // FIXME: Monitoring gamepads will also be reliant on whether or not there are any
     // connected/disconnected event listeners.
     // Those event listeners will also need to register with the GamepadManager.
-    if (m_navigators.size() == 1)
+    if (m_navigators.size() == 1) {
+        LOG(Gamepad, "GamepadManager registered first navigator, is starting gamepad monitoring");
         GamepadProvider::shared().startMonitoringGamepads(this);
+    }
 }
 
 void GamepadManager::unregisterNavigator(NavigatorGamepad* navigator)
 {
+    LOG(Gamepad, "GamepadManager unregistering NavigatorGamepad %p", navigator);
+
     ASSERT(m_navigators.contains(navigator));
     m_navigators.remove(navigator);
 
     // FIXME: Monitoring gamepads will also be reliant on whether or not there are any
     // connected/disconnected event listeners.
     // Those event listeners will also need to register with the GamepadManager.
-    if (m_navigators.isEmpty())
+    if (m_navigators.isEmpty()) {
+        LOG(Gamepad, "GamepadManager unregistered last navigator, is stopping gamepad monitoring");
         GamepadProvider::shared().stopMonitoringGamepads(this);
+    }
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/mac/HIDGamepadProvider.cpp (170548 => 170549)


--- trunk/Source/WebCore/platform/mac/HIDGamepadProvider.cpp	2014-06-27 20:31:31 UTC (rev 170548)
+++ trunk/Source/WebCore/platform/mac/HIDGamepadProvider.cpp	2014-06-27 20:35:55 UTC (rev 170549)
@@ -29,11 +29,13 @@
 #if ENABLE(GAMEPAD)
 
 #include "GamepadProviderClient.h"
+#include "Logging.h"
 #include "PlatformGamepad.h"
-#include <wtf/MainThread.h>
 
 namespace WebCore {
 
+static const double ConnectionDelayInterval = 0.5;
+
 static RetainPtr<CFDictionaryRef> deviceMatchingDictionary(uint32_t usagePage, uint32_t usage)
 {
     ASSERT(usagePage);
@@ -78,6 +80,7 @@
 
 HIDGamepadProvider::HIDGamepadProvider()
     : m_shouldDispatchCallbacks(false)
+    , m_connectionDelayTimer(this, &HIDGamepadProvider::connectionDelayTimerFired)
 {
     m_manager = adoptCF(IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone));
 
@@ -91,17 +94,7 @@
     IOHIDManagerSetDeviceMatchingMultiple(m_manager.get(), matchingArray.get());
     IOHIDManagerRegisterDeviceMatchingCallback(m_manager.get(), deviceAddedCallback, this);
     IOHIDManagerRegisterDeviceRemovalCallback(m_manager.get(), deviceRemovedCallback, this);
-    IOHIDManagerScheduleWithRunLoop(m_manager.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
-    IOHIDManagerOpen(m_manager.get(), kIOHIDOptionsTypeNone);
-
     IOHIDManagerRegisterInputValueCallback(m_manager.get(), deviceValuesChangedCallback, this);
-
-    // We'll immediately get a series of connection and value callbacks for already-connected gamepads
-    // but we don't want to notify WebCore of those events.
-    // This callOnMainThread call re-enables those callbacks after the runloop empties out.
-    callOnMainThread([]() {
-        HIDGamepadProvider::shared().setShouldDispatchCallbacks(true);
-    });
 }
 
 unsigned HIDGamepadProvider::indexForNewlyConnectedDevice()
@@ -113,19 +106,67 @@
     return index;
 }
 
+void HIDGamepadProvider::connectionDelayTimerFired(Timer<HIDGamepadProvider>&)
+{
+    m_shouldDispatchCallbacks = true;
+}
+
+void HIDGamepadProvider::openAndScheduleManager()
+{
+    LOG(Gamepad, "HIDGamepadProvider opening/scheduling HID manager");
+
+    ASSERT(m_gamepadVector.isEmpty());
+    ASSERT(m_gamepadMap.isEmpty());
+
+    m_shouldDispatchCallbacks = false;
+
+    IOHIDManagerScheduleWithRunLoop(m_manager.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDManagerOpen(m_manager.get(), kIOHIDOptionsTypeNone);
+
+    // Any connections we are notified of within the ConnectionDelayInterval of listening likely represent
+    // devices that were already connected, so we suppress notifying clients of these.
+    m_connectionDelayTimer.startOneShot(ConnectionDelayInterval);
+}
+
+void HIDGamepadProvider::closeAndUnscheduleManager()
+{
+    LOG(Gamepad, "HIDGamepadProvider closing/unscheduling HID manager");
+
+    IOHIDManagerUnscheduleFromRunLoop(m_manager.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDManagerClose(m_manager.get(), kIOHIDOptionsTypeNone);
+
+    m_gamepadVector.clear();
+    m_gamepadMap.clear();
+
+    m_connectionDelayTimer.stop();
+}
+
 void HIDGamepadProvider::startMonitoringGamepads(GamepadProviderClient* client)
 {
+    bool shouldOpenAndScheduleManager = m_clients.isEmpty();
+
+    ASSERT(!m_clients.contains(client));
     m_clients.add(client);
+
+    if (shouldOpenAndScheduleManager)
+        openAndScheduleManager();
 }
 void HIDGamepadProvider::stopMonitoringGamepads(GamepadProviderClient* client)
 {
-    m_clients.remove(client);
+    ASSERT(m_clients.contains(client));
+
+    bool shouldCloseAndUnscheduleManager = m_clients.remove(client) && m_clients.isEmpty();
+
+    if (shouldCloseAndUnscheduleManager)
+        closeAndUnscheduleManager();
 }
 
 void HIDGamepadProvider::deviceAdded(IOHIDDeviceRef device)
 {
     ASSERT(!m_gamepadMap.get(device));
 
+    LOG(Gamepad, "HIDGamepadProvider device %p added", device);
+
     std::unique_ptr<HIDGamepad> gamepad = std::make_unique<HIDGamepad>(device);
     unsigned index = indexForNewlyConnectedDevice();
 
@@ -135,8 +176,18 @@
     m_gamepadVector[index] = gamepad.get();
     m_gamepadMap.set(device, std::move(gamepad));
 
-    if (!m_shouldDispatchCallbacks)
+    if (!m_shouldDispatchCallbacks) {
+        // This added device is the result of us starting to monitor gamepads.
+        // We'll get notified of all connected devices during this current spin of the runloop
+        // and we don't want to tell the client about any of them.
+        // The m_connectionDelayTimer fires in a subsequent spin of the runloop after which
+        // any connection events are actual new devices.
+        m_connectionDelayTimer.startOneShot(0);
+
+        LOG(Gamepad, "Device %p was added while suppressing callbacks, so this should be an 'already connected' event", device);
+
         return;
+    }
 
     for (auto& client : m_clients)
         client->platformGamepadConnected(index);
@@ -144,11 +195,14 @@
 
 void HIDGamepadProvider::deviceRemoved(IOHIDDeviceRef device)
 {
+    LOG(Gamepad, "HIDGamepadProvider device %p removed", device);
+
     std::pair<std::unique_ptr<HIDGamepad>, unsigned> removedGamepad = removeGamepadForDevice(device);
     ASSERT(removedGamepad.first);
 
-    if (!m_shouldDispatchCallbacks)
-        return;
+    // Any time we get a device removed callback we know it's a real event and not an 'already connected' event.
+    // We should always stop supressing callbacks when we receive such an event.
+    m_shouldDispatchCallbacks = true;
 
     for (auto& client : m_clients)
         client->platformGamepadDisconnected(removedGamepad.second);

Modified: trunk/Source/WebCore/platform/mac/HIDGamepadProvider.h (170548 => 170549)


--- trunk/Source/WebCore/platform/mac/HIDGamepadProvider.h	2014-06-27 20:31:31 UTC (rev 170548)
+++ trunk/Source/WebCore/platform/mac/HIDGamepadProvider.h	2014-06-27 20:35:55 UTC (rev 170549)
@@ -30,6 +30,7 @@
 
 #include "GamepadProvider.h"
 #include "HIDGamepad.h"
+#include "Timer.h"
 #include <IOKit/hid/IOHIDManager.h>
 #include <wtf/Deque.h>
 #include <wtf/HashMap.h>
@@ -55,13 +56,16 @@
     void deviceRemoved(IOHIDDeviceRef);
     void valuesChanged(IOHIDValueRef);
 
-    void setShouldDispatchCallbacks(bool shouldDispatchCallbacks) { m_shouldDispatchCallbacks = shouldDispatchCallbacks; }
-
 private:
     HIDGamepadProvider();
 
     std::pair<std::unique_ptr<HIDGamepad>, unsigned> removeGamepadForDevice(IOHIDDeviceRef);
 
+    void openAndScheduleManager();
+    void closeAndUnscheduleManager();
+
+    void connectionDelayTimerFired(Timer<HIDGamepadProvider>&);
+
     unsigned indexForNewlyConnectedDevice();
 
     Vector<PlatformGamepad*> m_gamepadVector;
@@ -71,6 +75,8 @@
 
     HashSet<GamepadProviderClient*> m_clients;
     bool m_shouldDispatchCallbacks;
+
+    Timer<HIDGamepadProvider> m_connectionDelayTimer;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to