[GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
authorchangseok@webkit.org <changseok@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 May 2020 22:33:35 +0000 (22:33 +0000)
committerchangseok@webkit.org <changseok@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 May 2020 22:33:35 +0000 (22:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133854

Reviewed by Carlos Garcia Campos.

This patch brings initial GAMEPAD API support to the gtk port. We use libmanette,
a simple GObject game controller library to handle gamepad connection and input.
.:

* Source/cmake/FindManette.cmake: Added to detect libmanette headers and libs installed in host system.
* Source/cmake/OptionsGTK.cmake: Added a private flag, ENABLE_GAMEPAD.
  Once libmanette is found, we expose another build flag, USE_MANETTE for other ports.

Source/WebCore:

This change aims to implement two GAMEPAD API events: 'gamepadconnected' and 'gamepaddisconnected'
on top of libmanette. Rest of API will be implemented by following patches.

No new tests since existing tests can cover this change.

* PlatformGTK.cmake: Add header & library paths for libmanette.
* SourcesGTK.txt:
* platform/gamepad/manette/GUniquePtrManette.h: Added to define a smart pointer for ManetteMonitor.
* platform/gamepad/manette/ManetteGamepad.cpp: Added. A wrapper class for ManetteDevice.
  A ManetteGamepad instance is created per a physically connected gamepad. Currently,
  it is empty but input handling login will be placed in this class.
(WebCore::ManetteGamepad::ManetteGamepad):
* platform/gamepad/manette/ManetteGamepad.h: Added.
* platform/gamepad/manette/ManetteGamepadProvider.cpp: Added. A manager class
  for ManetteGamepad instances. This class represents ManetteMonitor that
  handles connection and disconnection of gamepads. Many parts of this class implementation
  is brought from HIDGamepad.cpp
(WebCore::ManetteGamepadProvider::singleton):
(WebCore::onDeviceConnected):
(WebCore::onDeviceDisconnected):
(WebCore::ManetteGamepadProvider::ManetteGamepadProvider):
(WebCore::ManetteGamepadProvider::startMonitoringGamepads):
(WebCore::ManetteGamepadProvider::stopMonitoringGamepads):
(WebCore::ManetteGamepadProvider::deviceConnected):
(WebCore::ManetteGamepadProvider::deviceDisconnected):
(WebCore::ManetteGamepadProvider::indexForNewlyConnectedDevice):
(WebCore::ManetteGamepadProvider::connectionDelayTimerFired):
(WebCore::ManetteGamepadProvider::removeGamepadForDevice):
* platform/gamepad/manette/ManetteGamepadProvider.h: Added.

Source/WebKit:

* SourcesGTK.txt:
* UIProcess/Gamepad/UIGamepadProvider.cpp: Add a build flag to void default interface
* UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp: Added to retrieve WebPageProxy to which
  a gamepad connects. The returned WebPageProxy handles input events from the gamepad.
(WebKit::getWebPageProxy):
(WebKit::UIGamepadProvider::platformWebPageProxyForGamepadInput):
* UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp: Added.
(WebKit::UIGamepadProvider::platformSetDefaultGamepadProvider):
(WebKit::UIGamepadProvider::platformWebPageProxyForGamepadInput):
(WebKit::UIGamepadProvider::platformStopMonitoringInput):
(WebKit::UIGamepadProvider::platformStartMonitoringInput):

Tools:

In particular, we use libmanette-0.2.4 which is the latest version and minimum
version to build in c++.

* gtk/jhbuild.modules:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261965 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
ChangeLog
Source/WebCore/ChangeLog
Source/WebCore/PlatformGTK.cmake
Source/WebCore/SourcesGTK.txt
Source/WebCore/platform/gamepad/manette/GUniquePtrManette.h [new file with mode: 0644]
Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp [new file with mode: 0644]
Source/WebCore/platform/gamepad/manette/ManetteGamepad.h [new file with mode: 0644]
Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp [new file with mode: 0644]
Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.h [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/SourcesGTK.txt
Source/WebKit/UIProcess/Gamepad/UIGamepadProvider.cpp
Source/WebKit/UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp [new file with mode: 0644]
Source/cmake/FindManette.cmake [new file with mode: 0644]
Source/cmake/OptionsGTK.cmake
Tools/ChangeLog
Tools/gtk/jhbuild.modules

index e0cf764..9483054 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2020-05-20  ChangSeok Oh  <changseok@webkit.org>
+
+        [GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
+        https://bugs.webkit.org/show_bug.cgi?id=133854
+
+        Reviewed by Carlos Garcia Campos.
+
+        This patch brings initial GAMEPAD API support to the gtk port. We use libmanette,
+        a simple GObject game controller library to handle gamepad connection and input.
+
+        * Source/cmake/FindManette.cmake: Added to detect libmanette headers and libs installed in host system.
+        * Source/cmake/OptionsGTK.cmake: Added a private flag, ENABLE_GAMEPAD.
+          Once libmanette is found, we expose another build flag, USE_MANETTE for other ports.
+
 2020-05-20  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Fix GTK4 build with GTK 3.98.4
index 0a17c56..62b3b45 100644 (file)
@@ -1,3 +1,42 @@
+2020-05-20  ChangSeok Oh  <changseok@webkit.org>
+
+        [GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
+        https://bugs.webkit.org/show_bug.cgi?id=133854
+
+        Reviewed by Carlos Garcia Campos.
+
+        This patch brings initial GAMEPAD API support to the gtk port. We use libmanette,
+        a simple GObject game controller library to handle gamepad connection and input.
+        This change aims to implement two GAMEPAD API events: 'gamepadconnected' and 'gamepaddisconnected'
+        on top of libmanette. Rest of API will be implemented by following patches.
+
+        No new tests since existing tests can cover this change.
+
+        * PlatformGTK.cmake: Add header & library paths for libmanette.
+        * SourcesGTK.txt:
+        * platform/gamepad/manette/GUniquePtrManette.h: Added to define a smart pointer for ManetteMonitor.
+        * platform/gamepad/manette/ManetteGamepad.cpp: Added. A wrapper class for ManetteDevice.
+          A ManetteGamepad instance is created per a physically connected gamepad. Currently,
+          it is empty but input handling login will be placed in this class.
+        (WebCore::ManetteGamepad::ManetteGamepad):
+        * platform/gamepad/manette/ManetteGamepad.h: Added.
+        * platform/gamepad/manette/ManetteGamepadProvider.cpp: Added. A manager class
+          for ManetteGamepad instances. This class represents ManetteMonitor that
+          handles connection and disconnection of gamepads. Many parts of this class implementation
+          is brought from HIDGamepad.cpp
+        (WebCore::ManetteGamepadProvider::singleton):
+        (WebCore::onDeviceConnected):
+        (WebCore::onDeviceDisconnected):
+        (WebCore::ManetteGamepadProvider::ManetteGamepadProvider):
+        (WebCore::ManetteGamepadProvider::startMonitoringGamepads):
+        (WebCore::ManetteGamepadProvider::stopMonitoringGamepads):
+        (WebCore::ManetteGamepadProvider::deviceConnected):
+        (WebCore::ManetteGamepadProvider::deviceDisconnected):
+        (WebCore::ManetteGamepadProvider::indexForNewlyConnectedDevice):
+        (WebCore::ManetteGamepadProvider::connectionDelayTimerFired):
+        (WebCore::ManetteGamepadProvider::removeGamepadForDevice):
+        * platform/gamepad/manette/ManetteGamepadProvider.h: Added.
+
 2020-05-20  Antoine Quint  <graouts@apple.com>
 
         Potential crash in PointerCaptureController::cancelPointer()
index ad7ada5..3b13a31 100644 (file)
@@ -162,6 +162,15 @@ if (ENABLE_WAYLAND_TARGET)
     )
 endif ()
 
+if (ENABLE_GAMEPAD)
+    list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
+        platform/gamepad/manette/ManetteGamepadProvider.h
+    )
+    list(APPEND WebCore_LIBRARIES
+        Manette::Manette
+    )
+endif ()
+
 include_directories(SYSTEM
     ${WebCore_SYSTEM_INCLUDE_DIRECTORIES}
 )
index 4dcff79..936e6a8 100644 (file)
@@ -67,6 +67,9 @@ platform/UserAgentQuirks.cpp
 platform/adwaita/ScrollbarThemeAdwaita.cpp
 platform/adwaita/ThemeAdwaita.cpp
 
+platform/gamepad/manette/ManetteGamepad.cpp
+platform/gamepad/manette/ManetteGamepadProvider.cpp
+
 platform/generic/ScrollAnimatorGeneric.cpp
 
 platform/graphics/GLContext.cpp @no-unify
diff --git a/Source/WebCore/platform/gamepad/manette/GUniquePtrManette.h b/Source/WebCore/platform/gamepad/manette/GUniquePtrManette.h
new file mode 100644 (file)
index 0000000..60037d4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 2020 Igalia S.L
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <wtf/Platform.h>
+
+#if USE(MANETTE)
+
+#include <libmanette.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace WTF {
+
+WTF_DEFINE_GPTR_DELETER(ManetteMonitorIter, manette_monitor_iter_free)
+
+} // namespace WTF
+
+#endif // USE(MANETTE)
diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp
new file mode 100644 (file)
index 0000000..1917963
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ManetteGamepad.h"
+
+#if ENABLE(GAMEPAD)
+
+namespace WebCore {
+
+ManetteGamepad::ManetteGamepad(ManetteDevice* device, unsigned index)
+    : PlatformGamepad(index)
+    , m_device(device)
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h
new file mode 100644 (file)
index 0000000..d70a859
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(GAMEPAD)
+
+#include "PlatformGamepad.h"
+
+#include <libmanette.h>
+#include <wtf/HashMap.h>
+#include <wtf/glib/GRefPtr.h>
+
+namespace WebCore {
+
+class ManetteGamepad final : public PlatformGamepad {
+public:
+    ManetteGamepad(ManetteDevice*, unsigned index);
+
+    const Vector<double>& axisValues() const final { return m_axisValues; }
+    const Vector<double>& buttonValues() const final { return m_buttonValues; }
+
+private:
+    GRefPtr<ManetteDevice> m_device;
+
+    Vector<double> m_buttonValues;
+    Vector<double> m_axisValues;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp
new file mode 100644 (file)
index 0000000..f2d7aa1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ManetteGamepadProvider.h"
+
+#if ENABLE(GAMEPAD)
+
+#include "GUniquePtrManette.h"
+#include "GamepadProviderClient.h"
+#include "Logging.h"
+#include "ManetteGamepad.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+static const Seconds connectionDelayInterval { 500_ms };
+
+ManetteGamepadProvider& ManetteGamepadProvider::singleton()
+{
+    static NeverDestroyed<ManetteGamepadProvider> sharedProvider;
+    return sharedProvider;
+}
+
+static void onDeviceConnected(ManetteMonitor*, ManetteDevice* device, ManetteGamepadProvider* provider)
+{
+    provider->deviceConnected(device);
+}
+
+static void onDeviceDisconnected(ManetteMonitor*, ManetteDevice* device, ManetteGamepadProvider* provider)
+{
+    provider->deviceDisconnected(device);
+}
+
+ManetteGamepadProvider::ManetteGamepadProvider()
+    : m_monitor(manette_monitor_new())
+    , m_connectionDelayTimer(RunLoop::current(), this, &ManetteGamepadProvider::connectionDelayTimerFired)
+{
+    g_signal_connect(m_monitor.get(), "device-connected", G_CALLBACK(onDeviceConnected), this);
+    g_signal_connect(m_monitor.get(), "device-disconnected", G_CALLBACK(onDeviceDisconnected), this);
+}
+
+void ManetteGamepadProvider::startMonitoringGamepads(GamepadProviderClient& client)
+{
+    bool shouldOpenAndScheduleManager = m_clients.isEmpty();
+
+    ASSERT(!m_clients.contains(&client));
+    m_clients.add(&client);
+
+    if (!shouldOpenAndScheduleManager)
+        return;
+
+    ASSERT(m_gamepadVector.isEmpty());
+    ASSERT(m_gamepadMap.isEmpty());
+
+    m_shouldDispatchCallbacks = false;
+    m_connectionDelayTimer.startOneShot(connectionDelayInterval);
+}
+
+void ManetteGamepadProvider::stopMonitoringGamepads(GamepadProviderClient& client)
+{
+    ASSERT(m_clients.contains(&client));
+
+    bool shouldCloseAndUnscheduleManager = m_clients.remove(&client) && m_clients.isEmpty();
+    if (shouldCloseAndUnscheduleManager) {
+        m_gamepadVector.clear();
+        m_gamepadMap.clear();
+        m_connectionDelayTimer.stop();
+    }
+}
+
+void ManetteGamepadProvider::deviceConnected(ManetteDevice* device)
+{
+    ASSERT(!m_gamepadMap.get(device));
+
+    LOG(Gamepad, "ManetteGamepadProvider device %p added", device);
+
+    unsigned index = indexForNewlyConnectedDevice();
+    auto gamepad = makeUnique<ManetteGamepad>(device, index);
+
+    if (m_gamepadVector.size() <= index)
+        m_gamepadVector.grow(index + 1);
+
+    m_gamepadVector[index] = gamepad.get();
+    m_gamepadMap.set(device, WTFMove(gamepad));
+
+    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_s);
+
+        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(*m_gamepadVector[index]);
+}
+
+void ManetteGamepadProvider::deviceDisconnected(ManetteDevice* device)
+{
+    LOG(Gamepad, "ManetteGamepadProvider device %p removed", device);
+
+    std::unique_ptr<ManetteGamepad> removedGamepad = removeGamepadForDevice(device);
+    ASSERT(removedGamepad);
+
+    // 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 suppressing callbacks when we receive such an event.
+    m_shouldDispatchCallbacks = true;
+
+    for (auto& client : m_clients)
+        client->platformGamepadDisconnected(*removedGamepad);
+}
+
+unsigned ManetteGamepadProvider::indexForNewlyConnectedDevice()
+{
+    unsigned index = 0;
+    while (index < m_gamepadVector.size() && m_gamepadVector[index])
+        ++index;
+
+    return index;
+}
+
+void ManetteGamepadProvider::connectionDelayTimerFired()
+{
+    m_shouldDispatchCallbacks = true;
+
+    for (auto* client : m_clients)
+        client->setInitialConnectedGamepads(m_gamepadVector);
+}
+
+std::unique_ptr<ManetteGamepad> ManetteGamepadProvider::removeGamepadForDevice(ManetteDevice* device)
+{
+    std::unique_ptr<ManetteGamepad> result = m_gamepadMap.take(device);
+    ASSERT(result);
+
+    auto index = m_gamepadVector.find(result.get());
+    if (index != notFound)
+        m_gamepadVector[index] = nullptr;
+
+    return result;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.h b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.h
new file mode 100644 (file)
index 0000000..c7363a3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(GAMEPAD)
+
+#include "GamepadProvider.h"
+#include <libmanette.h>
+#include <wtf/HashMap.h>
+#include <wtf/RunLoop.h>
+
+namespace WebCore {
+
+class ManetteGamepad;
+class GamepadProviderClient;
+
+class ManetteGamepadProvider final : public GamepadProvider {
+    WTF_MAKE_NONCOPYABLE(ManetteGamepadProvider);
+    friend class NeverDestroyed<ManetteGamepadProvider>;
+public:
+    static ManetteGamepadProvider& singleton();
+
+    void startMonitoringGamepads(GamepadProviderClient&) final;
+    void stopMonitoringGamepads(GamepadProviderClient&) final;
+    const Vector<PlatformGamepad*>& platformGamepads() final { return m_gamepadVector; }
+
+    void deviceConnected(ManetteDevice*);
+    void deviceDisconnected(ManetteDevice*);
+
+private:
+    ManetteGamepadProvider();
+
+    std::unique_ptr<ManetteGamepad> removeGamepadForDevice(ManetteDevice*);
+
+    unsigned indexForNewlyConnectedDevice();
+    void connectionDelayTimerFired();
+
+    Vector<PlatformGamepad*> m_gamepadVector;
+    HashMap<ManetteDevice*, std::unique_ptr<ManetteGamepad>> m_gamepadMap;
+    bool m_shouldDispatchCallbacks { false };
+
+    GUniquePtr<ManetteMonitor> m_monitor;
+    RunLoop::Timer<ManetteGamepadProvider> m_connectionDelayTimer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
index 75588a7..c92d778 100644 (file)
@@ -1,3 +1,25 @@
+2020-05-20  ChangSeok Oh  <changseok@webkit.org>
+
+        [GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
+        https://bugs.webkit.org/show_bug.cgi?id=133854
+
+        Reviewed by Carlos Garcia Campos.
+
+        This patch brings initial GAMEPAD API support to the gtk port. We use libmanette,
+        a simple GObject game controller library to handle gamepad connection and input.
+
+        * SourcesGTK.txt:
+        * UIProcess/Gamepad/UIGamepadProvider.cpp: Add a build flag to void default interface
+        * UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp: Added to retrieve WebPageProxy to which
+          a gamepad connects. The returned WebPageProxy handles input events from the gamepad.
+        (WebKit::getWebPageProxy):
+        (WebKit::UIGamepadProvider::platformWebPageProxyForGamepadInput):
+        * UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp: Added.
+        (WebKit::UIGamepadProvider::platformSetDefaultGamepadProvider):
+        (WebKit::UIGamepadProvider::platformWebPageProxyForGamepadInput):
+        (WebKit::UIGamepadProvider::platformStopMonitoringInput):
+        (WebKit::UIGamepadProvider::platformStartMonitoringInput):
+
 2020-05-20  Kate Cheney  <katherine_cheney@apple.com>
 
         Support operating dates in ResourceLoadStatisticsDatabaseStore
index 7d78450..2d5aac9 100644 (file)
@@ -222,6 +222,9 @@ UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp
 
 UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp
 
+UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp
+UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp
+
 UIProcess/geoclue/GeoclueGeolocationProvider.cpp
 
 UIProcess/Inspector/glib/RemoteInspectorClient.cpp
index f4b7bea..c6dd4e0 100644 (file)
@@ -223,7 +223,7 @@ Vector<GamepadData> UIGamepadProvider::snapshotGamepads()
     return gamepadDatas;
 }
 
-#if !PLATFORM(COCOA)
+#if !PLATFORM(COCOA) && !USE(MANETTE)
 
 void UIGamepadProvider::platformSetDefaultGamepadProvider()
 {
@@ -244,7 +244,7 @@ void UIGamepadProvider::platformStartMonitoringInput()
 {
 }
 
-#endif // !PLATFORM(MAC)
+#endif // !PLATFORM(COCOA) && !USE(MANETTE)
 
 }
 
diff --git a/Source/WebKit/UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp b/Source/WebKit/UIProcess/Gamepad/gtk/UIGamepadProviderGtk.cpp
new file mode 100644 (file)
index 0000000..7877747
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UIGamepadProvider.h"
+
+#if ENABLE(GAMEPAD)
+
+#include "WebKitWebViewBasePrivate.h"
+#include "WebPageProxy.h"
+#include <WebCore/GtkUtilities.h>
+#include <wtf/ProcessPrivilege.h>
+#include <wtf/glib/GRefPtr.h>
+
+namespace WebKit {
+
+using namespace WebCore;
+
+static WebPageProxy* getWebPageProxy(GtkWidget* widget)
+{
+    if (!widget || !GTK_IS_CONTAINER(widget))
+        return nullptr;
+
+    if (WEBKIT_IS_WEB_VIEW(widget))
+        return gtk_widget_is_visible(widget) ? webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(widget)) : nullptr;
+
+    GUniquePtr<GList> children(gtk_container_get_children(GTK_CONTAINER(widget)));
+    for (GList* iter = children.get(); iter; iter= g_list_next(iter)) {
+        if (WebPageProxy* proxy = getWebPageProxy(GTK_WIDGET(iter->data)))
+            return proxy;
+    }
+    return nullptr;
+}
+
+WebPageProxy* UIGamepadProvider::platformWebPageProxyForGamepadInput()
+{
+    GUniquePtr<GList> toplevels(gtk_window_list_toplevels());
+    for (GList* iter = toplevels.get(); iter; iter = g_list_next(iter)) {
+        if (!WebCore::widgetIsOnscreenToplevelWindow(GTK_WIDGET(iter->data)))
+            continue;
+
+        GtkWindow* window = GTK_WINDOW(iter->data);
+        if (!gtk_window_has_toplevel_focus(window))
+            continue;
+
+        if (WebPageProxy* proxy = getWebPageProxy(GTK_WIDGET(window)))
+            return proxy;
+    }
+    return nullptr;
+}
+
+}
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp b/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp
new file mode 100644 (file)
index 0000000..add2cab
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UIGamepadProvider.h"
+
+#if ENABLE(GAMEPAD)
+
+#include "WebPageProxy.h"
+#include <WebCore/ManetteGamepadProvider.h>
+#include <wtf/ProcessPrivilege.h>
+
+namespace WebKit {
+
+using namespace WebCore;
+
+void UIGamepadProvider::platformSetDefaultGamepadProvider()
+{
+    if (GamepadProvider::singleton().isMockGamepadProvider())
+        return;
+
+    GamepadProvider::setSharedProvider(ManetteGamepadProvider::singleton());
+}
+
+#if !PLATFORM(GTK)
+WebPageProxy* UIGamepadProvider::platformWebPageProxyForGamepadInput()
+{
+    return nullptr;
+}
+#endif
+
+void UIGamepadProvider::platformStopMonitoringInput()
+{
+}
+
+void UIGamepadProvider::platformStartMonitoringInput()
+{
+}
+
+}
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/cmake/FindManette.cmake b/Source/cmake/FindManette.cmake
new file mode 100644 (file)
index 0000000..e834c0a
--- /dev/null
@@ -0,0 +1,72 @@
+# Copyright (C) 2020 Igalia S.L.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+#[=======================================================================[.rst:
+FindManette
+-----------
+
+Find Manette headers and libraries.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+``Manette::Manette``
+  The Manette library, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This will define the following variables in your project:
+
+``Manette_FOUND``
+  true if (the requested version of) Manette is available.
+``Manette_VERSION``
+  the version of Manette.
+``Manette_LIBRARIES``
+  the libraries to link against to use Manette.
+``Manette_INCLUDE_DIRS``
+  where to find the Manette headers.
+``Manette_COMPILE_OPTIONS``
+  this should be passed to target_compile_options(), if the
+  target is not used for linking
+
+#]=======================================================================]
+
+find_package(PkgConfig)
+pkg_check_modules(PC_MANETTE IMPORTED_TARGET manette-0.2)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Manette
+    FOUND_VAR Manette_FOUND
+    REQUIRED_VARS Manette_INCLUDE_DIR Manette_LIBRARY
+    VERSION_VAR Manette_VERSION
+)
+
+if (TARGET PkgConfig::PC_MANETTE AND NOT TARGET Manette::Manette)
+    add_library(Manette::Manette INTERFACE IMPORTED GLOBAL)
+    set_property(TARGET Manette::Manette PROPERTY
+        INTERFACE_LINK_LIBRARIES PkgConfig::PC_MANETTE
+    )
+endif ()
+
+mark_as_advanced(Manette_INCLUDE_DIR Manette_LIBRARY)
index 17a4aad..7570fbc 100644 (file)
@@ -177,6 +177,7 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DATALIST_ELEMENT PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DOWNLOAD_ATTRIBUTE PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ENCRYPTED_MEDIA PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES})
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PRIVATE OFF)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GPU_PROCESS PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES})
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_COLOR PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LAYOUT_FORMATTING_CONTEXT PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES})
@@ -244,6 +245,14 @@ if (USE_WPE_RENDERER)
     endif ()
 endif ()
 
+if (ENABLE_GAMEPAD)
+    find_package(Manette 0.2.4 REQUIRED)
+    if (NOT Manette_FOUND)
+        message(FATAL_ERROR "libmanette is required for ENABLE_GAMEPAD")
+    endif ()
+    SET_AND_EXPOSE_TO_BUILD(USE_MANETTE TRUE)
+endif ()
+
 if (ENABLE_XSLT)
     find_package(LibXslt 1.1.7 REQUIRED)
 endif ()
index 2ae6050..5016e55 100644 (file)
@@ -1,3 +1,17 @@
+2020-05-20  ChangSeok Oh  <changseok@webkit.org>
+
+        [GTK] Implement connected and disconnected events of GAMEPAD API with libmanette
+        https://bugs.webkit.org/show_bug.cgi?id=133854
+
+        Reviewed by Carlos Garcia Campos.
+
+        This patch brings initial GAMEPAD API support to the gtk port. We use libmanette,
+        a simple GObject game controller library to handle gamepad connection and input.
+        In particular, we use libmanette-0.2.4 which is the latest version and minimum
+        version to build in c++.
+
+        * gtk/jhbuild.modules:
+
 2020-05-20  Kate Cheney  <katherine_cheney@apple.com>
 
         Support operating dates in ResourceLoadStatisticsDatabaseStore
index 7fcf706..f4995e0 100644 (file)
@@ -29,6 +29,7 @@
       <dep package="libsecret"/>
       <dep package="libgpg-error"/>
       <dep package="libgcrypt"/>
+      <dep package="manette"/>
       <dep package="openjpeg"/>
       <dep package="wpebackend-fdo"/>
       <if condition-set="linux">
     </dependencies>
   </autotools>
 
+  <meson id="manette" mesonargs="-Dintrospection=false -Dvapi=false">
+    <branch repo="ftp.gnome.org"
+            module="/pub/gnome/sources/libmanette/0.2/libmanette-0.2.4.tar.xz"
+            version="0.2.4"
+            hash="sha256:4fe0a4bed6b4c3ae7249d341031c27b32f8d9e0ffb5337d71cbcec7160362cf7">
+    </branch>
+    <dependencies>
+      <dep package="glib"/>
+    </dependencies>
+  </meson>
+
   <cmake id="openjpeg">
     <branch repo="github-tarball"
             module="uclouvain/openjpeg/archive/v${version}.tar.gz"