[Gtk] Add support for the Gamepad API
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Jun 2012 09:19:15 +0000 (09:19 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Jun 2012 09:19:15 +0000 (09:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=87503

Reviewed by Carlos Garcia Campos.

.:

Only enable the Gamepad feature on Linux as support
for other operating systems is not present.

Check for the GIO Unix and GUdev dependencies when the
Gamepad feature is enabled.

* configure.ac:

Source/WebCore:

Add support for the Gamepad feature on the GTK port.

The support is available only on Linux, with each gamepad device being presented
through a GamepadDeviceLinux object. The implementation of this class relies on
the Linux kernel joystick API.

Gamepad devices are recognized through the GamepadsGtk class, of which implementation
is based on GUdev. This way devices are properly registered on connection as objects of
the GamepadDeviceGtk class which inherits GamepadDeviceLinux. GamepadDeviceGtk reads the
joystick data through GIO pollable streams and updates the device state accordingly. The
GamepadsGtk object is then polled for gamepads data through the sampleGamepads method.

No new tests - tests already exist but require additional testing infrastructure.

* GNUmakefile.am:
* GNUmakefile.list.am:
* bindings/gobject/GNUmakefile.am:
* bindings/js/JSDOMBinding.h: Add the jsArray method that operates on a Vector of floats.
(WebCore):
(WebCore::jsArray):
* platform/gtk/GamepadsGtk.cpp: Added.
(WebCore):
(GamepadDeviceGtk):
(WebCore::GamepadDeviceGtk::create):
(WebCore::GamepadDeviceGtk::GamepadDeviceGtk):
(WebCore::GamepadDeviceGtk::~GamepadDeviceGtk):
(WebCore::GamepadDeviceGtk::readCallback):
(GamepadsGtk):
(WebCore::GamepadsGtk::GamepadsGtk):
(WebCore::GamepadsGtk::~GamepadsGtk):
(WebCore::GamepadsGtk::registerDevice):
(WebCore::GamepadsGtk::unregisterDevice):
(WebCore::GamepadsGtk::updateGamepadList):
(WebCore::GamepadsGtk::onUEventCallback):
(WebCore::GamepadsGtk::isGamepadDevice):
(WebCore::sampleGamepads):
* platform/linux/GamepadDeviceLinux.cpp: Added.
(WebCore):
(WebCore::GamepadDeviceLinux::GamepadDeviceLinux):
(WebCore::GamepadDeviceLinux::~GamepadDeviceLinux):
(WebCore::GamepadDeviceLinux::updateForEvent):
(WebCore::GamepadDeviceLinux::normalizeAxisValue):
(WebCore::GamepadDeviceLinux::normalizeButtonValue):
* platform/linux/GamepadDeviceLinux.h: Added.
(WebCore):
(GamepadDeviceLinux):
(WebCore::GamepadDeviceLinux::connected):
(WebCore::GamepadDeviceLinux::id):
(WebCore::GamepadDeviceLinux::timestamp):
(WebCore::GamepadDeviceLinux::axesCount):
(WebCore::GamepadDeviceLinux::axesData):
(WebCore::GamepadDeviceLinux::buttonsCount):
(WebCore::GamepadDeviceLinux::buttonsData):

Source/WebKit/gtk:

Add the Gamepad feature dependencies libraries to the LIBADD
list for the libwebkitgtk library.

* GNUmakefile.am:

Source/WebKit2:

Add the Gamepad feature dependencies libraries to the LIBADD
list for the libwebkitgtk2 library.

* GNUmakefile.am:

Tools:

Enable the gamepad support for the GTK port.

* Scripts/webkitperl/FeatureList.pm:

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

16 files changed:
ChangeLog
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.am
Source/WebCore/GNUmakefile.list.am
Source/WebCore/bindings/gobject/GNUmakefile.am
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/platform/gtk/GamepadsGtk.cpp [new file with mode: 0644]
Source/WebCore/platform/linux/GamepadDeviceLinux.cpp [new file with mode: 0644]
Source/WebCore/platform/linux/GamepadDeviceLinux.h [new file with mode: 0644]
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/GNUmakefile.am
Source/WebKit2/ChangeLog
Source/WebKit2/GNUmakefile.am
Tools/ChangeLog
Tools/Scripts/webkitperl/FeatureList.pm
configure.ac

index 72a7486..2c398fa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2012-06-27  Zan Dobersek  <zandobersek@gmail.com>
+
+        [Gtk] Add support for the Gamepad API
+        https://bugs.webkit.org/show_bug.cgi?id=87503
+
+        Reviewed by Carlos Garcia Campos.
+
+        Only enable the Gamepad feature on Linux as support
+        for other operating systems is not present.
+
+        Check for the GIO Unix and GUdev dependencies when the
+        Gamepad feature is enabled.
+
+        * configure.ac:
+
 2012-06-25  Simon Hausmann  <simon.hausmann@nokia.com>
 
         [Qt] Make it possible to build WebKit without QtWidgets
index 5d45e14..bcac38b 100755 (executable)
@@ -1,3 +1,64 @@
+2012-06-27  Zan Dobersek  <zandobersek@gmail.com>
+
+        [Gtk] Add support for the Gamepad API
+        https://bugs.webkit.org/show_bug.cgi?id=87503
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add support for the Gamepad feature on the GTK port.
+
+        The support is available only on Linux, with each gamepad device being presented
+        through a GamepadDeviceLinux object. The implementation of this class relies on
+        the Linux kernel joystick API.
+
+        Gamepad devices are recognized through the GamepadsGtk class, of which implementation
+        is based on GUdev. This way devices are properly registered on connection as objects of
+        the GamepadDeviceGtk class which inherits GamepadDeviceLinux. GamepadDeviceGtk reads the
+        joystick data through GIO pollable streams and updates the device state accordingly. The
+        GamepadsGtk object is then polled for gamepads data through the sampleGamepads method.
+
+        No new tests - tests already exist but require additional testing infrastructure.
+
+        * GNUmakefile.am:
+        * GNUmakefile.list.am:
+        * bindings/gobject/GNUmakefile.am:
+        * bindings/js/JSDOMBinding.h: Add the jsArray method that operates on a Vector of floats.
+        (WebCore):
+        (WebCore::jsArray):
+        * platform/gtk/GamepadsGtk.cpp: Added.
+        (WebCore):
+        (GamepadDeviceGtk):
+        (WebCore::GamepadDeviceGtk::create):
+        (WebCore::GamepadDeviceGtk::GamepadDeviceGtk):
+        (WebCore::GamepadDeviceGtk::~GamepadDeviceGtk):
+        (WebCore::GamepadDeviceGtk::readCallback):
+        (GamepadsGtk):
+        (WebCore::GamepadsGtk::GamepadsGtk):
+        (WebCore::GamepadsGtk::~GamepadsGtk):
+        (WebCore::GamepadsGtk::registerDevice):
+        (WebCore::GamepadsGtk::unregisterDevice):
+        (WebCore::GamepadsGtk::updateGamepadList):
+        (WebCore::GamepadsGtk::onUEventCallback):
+        (WebCore::GamepadsGtk::isGamepadDevice):
+        (WebCore::sampleGamepads):
+        * platform/linux/GamepadDeviceLinux.cpp: Added.
+        (WebCore):
+        (WebCore::GamepadDeviceLinux::GamepadDeviceLinux):
+        (WebCore::GamepadDeviceLinux::~GamepadDeviceLinux):
+        (WebCore::GamepadDeviceLinux::updateForEvent):
+        (WebCore::GamepadDeviceLinux::normalizeAxisValue):
+        (WebCore::GamepadDeviceLinux::normalizeButtonValue):
+        * platform/linux/GamepadDeviceLinux.h: Added.
+        (WebCore):
+        (GamepadDeviceLinux):
+        (WebCore::GamepadDeviceLinux::connected):
+        (WebCore::GamepadDeviceLinux::id):
+        (WebCore::GamepadDeviceLinux::timestamp):
+        (WebCore::GamepadDeviceLinux::axesCount):
+        (WebCore::GamepadDeviceLinux::axesData):
+        (WebCore::GamepadDeviceLinux::buttonsCount):
+        (WebCore::GamepadDeviceLinux::buttonsData):
+
 2012-06-27  Kentaro Hara  <haraken@chromium.org>
 
         Rename rareSVGData() to svgRareData()
index f328077..eae0a71 100644 (file)
@@ -12,6 +12,7 @@ webcore_cppflags += \
        -I$(srcdir)/Source/ThirdParty/ANGLE/include/GLSLANG \
        -I$(srcdir)/Source/WebCore \
        -I$(srcdir)/Source/WebCore/Modules/filesystem \
+       -I$(srcdir)/Source/WebCore/Modules/gamepad \
        -I$(srcdir)/Source/WebCore/Modules/geolocation \
        -I$(srcdir)/Source/WebCore/Modules/indexeddb \
        -I$(srcdir)/Source/WebCore/Modules/mediastream \
@@ -67,6 +68,7 @@ webcore_cppflags += \
        -I$(srcdir)/Source/WebCore/platform/image-decoders/webp \
        -I$(srcdir)/Source/WebCore/platform/image-decoders/png \
        -I$(srcdir)/Source/WebCore/platform/leveldb \
+       -I$(srcdir)/Source/WebCore/platform/linux \
        -I$(srcdir)/Source/WebCore/platform/mediastream \
        -I$(srcdir)/Source/WebCore/platform/mediastream/gstreamer \
        -I$(srcdir)/Source/WebCore/platform/mock \
@@ -866,6 +868,7 @@ DerivedSources/ANGLE/glslang_tab.h: DerivedSources/ANGLE/glslang_tab.cpp
 
 IDL_PATH := \
     $(WebCore)/Modules/filesystem \
+    $(WebCore)/Modules/gamepad \
     $(WebCore)/Modules/geolocation \
     $(WebCore)/Modules/indexeddb \
     $(WebCore)/Modules/mediastream \
@@ -961,6 +964,7 @@ libWebCore_la_CPPFLAGS = \
        $(CLUTTER_CFLAGS) \
        $(COVERAGE_CFLAGS) \
        $(ENCHANT_CFLAGS) \
+       $(GAMEPAD_CFLAGS) \
        $(GEOCLUE_CFLAGS) \
        $(GLIB_CFLAGS) \
        $(GSTREAMER_CFLAGS) \
@@ -1032,6 +1036,7 @@ libWebCoreGtk_la_CPPFLAGS = \
 
 EXTRA_DIST += \
        $(shell ls $(srcdir)/Source/WebCore/Modules/filesystem/*.idl) \
+       $(shell ls $(srcdir)/Source/WebCore/Modules/gamepad/*.idl) \
        $(shell ls $(srcdir)/Source/WebCore/Modules/geolocation/*.idl) \
        $(shell ls $(srcdir)/Source/WebCore/Modules/indexeddb/*.idl) \
        $(shell ls $(srcdir)/Source/WebCore/Modules/mediastream/*.idl) \
index 2a14316..35ec2ec 100644 (file)
@@ -192,6 +192,10 @@ webcore_built_sources += \
        DerivedSources/WebCore/JSFloat32Array.h \
        DerivedSources/WebCore/JSFloat64Array.cpp \
        DerivedSources/WebCore/JSFloat64Array.h \
+       DerivedSources/WebCore/JSGamepad.cpp \
+       DerivedSources/WebCore/JSGamepad.h \
+       DerivedSources/WebCore/JSGamepadList.cpp \
+       DerivedSources/WebCore/JSGamepadList.h \
        DerivedSources/WebCore/JSGeolocation.cpp \
        DerivedSources/WebCore/JSGeolocation.h \
        DerivedSources/WebCore/JSGeoposition.cpp \
@@ -677,6 +681,9 @@ webcore_built_sources += \
        DerivedSources/WebCore/XPathGrammar.h
 
 dom_binding_idls += \
+       $(WebCore)/Modules/gamepad/Gamepad.idl \
+       $(WebCore)/Modules/gamepad/GamepadList.idl \
+       $(WebCore)/Modules/gamepad/NavigatorGamepad.idl \
        $(WebCore)/Modules/geolocation/Geolocation.idl \
        $(WebCore)/Modules/geolocation/Geoposition.idl \
        $(WebCore)/Modules/geolocation/NavigatorGeolocation.idl \
@@ -1053,6 +1060,12 @@ webcore_modules_sources += \
        Source/WebCore/Modules/filesystem/WebKitFlags.h \
        Source/WebCore/Modules/filesystem/WorkerContextFileSystem.cpp \
        Source/WebCore/Modules/filesystem/WorkerContextFileSystem.h \
+       Source/WebCore/Modules/gamepad/Gamepad.cpp \
+       Source/WebCore/Modules/gamepad/Gamepad.h \
+       Source/WebCore/Modules/gamepad/GamepadList.cpp \
+       Source/WebCore/Modules/gamepad/GamepadList.h \
+       Source/WebCore/Modules/gamepad/NavigatorGamepad.cpp \
+       Source/WebCore/Modules/gamepad/NavigatorGamepad.h \
        Source/WebCore/Modules/geolocation/Geolocation.cpp \
        Source/WebCore/Modules/geolocation/Geolocation.h \
        Source/WebCore/Modules/geolocation/GeolocationController.cpp \
@@ -3160,6 +3173,7 @@ webcore_sources += \
        Source/WebCore/platform/FileSystem.h \
        Source/WebCore/platform/FloatConversion.h \
        Source/WebCore/platform/FractionalLayoutUnit.h \
+       Source/WebCore/platform/Gamepads.h \
        Source/WebCore/platform/HashTools.h \
        Source/WebCore/platform/HistogramSupport.cpp \
        Source/WebCore/platform/HistogramSupport.h \
@@ -3408,6 +3422,7 @@ webcore_sources += \
        Source/WebCore/platform/graphics/WOFFFileFormat.h \
        Source/WebCore/platform/gtk/ErrorsGtk.cpp \
        Source/WebCore/platform/gtk/ErrorsGtk.h \
+       Source/WebCore/platform/gtk/GamepadsGtk.cpp \
        Source/WebCore/platform/gtk/KURLGtk.cpp \
        Source/WebCore/platform/gtk/LanguageGtk.cpp \
        Source/WebCore/platform/gtk/LoggingGtk.cpp \
@@ -3468,6 +3483,8 @@ webcore_sources += \
        Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h \
        Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp \
        Source/WebCore/platform/image-decoders/png/PNGImageDecoder.h \
+       Source/WebCore/platform/linux/GamepadDeviceLinux.cpp \
+       Source/WebCore/platform/linux/GamepadDeviceLinux.h \
        Source/WebCore/platform/mediastream/DeprecatedPeerConnectionHandler.h \
        Source/WebCore/platform/mediastream/DeprecatedPeerConnectionHandlerClient.h \
        Source/WebCore/platform/mediastream/IceCandidateDescriptor.cpp \
index c702528..fa04542 100644 (file)
@@ -66,6 +66,10 @@ webkitgtk_gdom_built_sources += \
        DerivedSources/webkit/WebKitDOMFileList.cpp \
        DerivedSources/webkit/WebKitDOMFileListPrivate.h \
        DerivedSources/webkit/WebKitDOMFilePrivate.h \
+       DerivedSources/webkit/WebKitDOMGamepad.cpp \
+       DerivedSources/webkit/WebKitDOMGamepadList.cpp \
+       DerivedSources/webkit/WebKitDOMGamepadListPrivate.h \
+       DerivedSources/webkit/WebKitDOMGamepadPrivate.h \
        DerivedSources/webkit/WebKitDOMGeolocation.cpp \
        DerivedSources/webkit/WebKitDOMGeolocationPrivate.h \
        DerivedSources/webkit/WebKitDOMHistory.cpp \
@@ -295,6 +299,8 @@ webkitgtk_built_h_api += \
        DerivedSources/webkit/WebKitDOMBlob.h \
        DerivedSources/webkit/WebKitDOMFile.h \
        DerivedSources/webkit/WebKitDOMFileList.h \
+       DerivedSources/webkit/WebKitDOMGamepad.h \
+       DerivedSources/webkit/WebKitDOMGamepadList.h \
        DerivedSources/webkit/WebKitDOMGeolocation.h \
        DerivedSources/webkit/WebKitDOMHTMLAnchorElement.h \
        DerivedSources/webkit/WebKitDOMHTMLAppletElement.h \
@@ -428,7 +434,6 @@ webkitgtk_gdom_built_sources += \
        DerivedSources/webkit/WebKitDOMHTMLPropertiesCollectionPrivate.h
 endif
 
-
 if ENABLE_WEB_TIMING
 webkitgtk_built_h_api += \
        $(top_builddir)/DerivedSources/webkit/WebKitDOMPerformance.h \
index d278a80..b5ad3fb 100644 (file)
@@ -307,6 +307,18 @@ enum ParameterDefaultPolicy {
         return JSC::constructArray(exec, globalObject, array);
     }
 
+    template<>
+    inline JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<float>& iterator)
+    {
+        JSC::MarkedArgumentBuffer array;
+        Vector<float>::const_iterator end = iterator.end();
+
+        for (Vector<float>::const_iterator it = iterator.begin(); it != end; ++it)
+            array.append(JSC::jsNumber(*it));
+
+        return JSC::constructArray(exec, globalObject, array);
+    }
+
     template <class T>
     Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value)
     {
diff --git a/Source/WebCore/platform/gtk/GamepadsGtk.cpp b/Source/WebCore/platform/gtk/GamepadsGtk.cpp
new file mode 100644 (file)
index 0000000..b39395b
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
+ *
+ * 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 "Gamepads.h"
+
+#if ENABLE(GAMEPAD)
+
+#include "GamepadDeviceLinux.h"
+#include "GamepadList.h"
+#include <gio/gunixinputstream.h>
+#include <gudev/gudev.h>
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/gobject/GOwnPtr.h>
+#include <wtf/gobject/GRefPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class GamepadDeviceGtk : public GamepadDeviceLinux {
+public:
+    static PassOwnPtr<GamepadDeviceGtk> create(String deviceFile)
+    {
+        return adoptPtr(new GamepadDeviceGtk(deviceFile));
+    }
+    ~GamepadDeviceGtk();
+
+private:
+    GamepadDeviceGtk(String deviceFile);
+
+    static gboolean readCallback(GObject* pollableStream, gpointer data);
+    GRefPtr<GInputStream> m_inputStream;
+    GRefPtr<GSource> m_source;
+};
+
+GamepadDeviceGtk::GamepadDeviceGtk(String deviceFile)
+    : GamepadDeviceLinux(deviceFile)
+{
+    if (m_fileDescriptor == -1)
+        return;
+
+    m_inputStream = adoptGRef(g_unix_input_stream_new(m_fileDescriptor, FALSE));
+    m_source = adoptGRef(g_pollable_input_stream_create_source(G_POLLABLE_INPUT_STREAM(m_inputStream.get()), 0));
+    g_source_set_callback(m_source.get(), reinterpret_cast<GSourceFunc>(readCallback), this, 0);
+    g_source_attach(m_source.get(), 0);
+}
+
+GamepadDeviceGtk::~GamepadDeviceGtk()
+{
+    if (m_source)
+        g_source_destroy(m_source.get());
+}
+
+gboolean GamepadDeviceGtk::readCallback(GObject* pollableStream, gpointer data)
+{
+    GamepadDeviceGtk* gamepadDevice = reinterpret_cast<GamepadDeviceGtk*>(data);
+    GOwnPtr<GError> error;
+    struct js_event event;
+
+    gssize len = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(pollableStream),
+                                                          &event, sizeof(event), 0, &error.outPtr());
+
+    // FIXME: Properly log the error.
+    // In the case of G_IO_ERROR_WOULD_BLOCK error return TRUE to wait until
+    // the source becomes readable again and FALSE otherwise.
+    if (error)
+        return g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
+
+    ASSERT(len == sizeof(event));
+    gamepadDevice->updateForEvent(event);
+    return TRUE;
+}
+
+class GamepadsGtk {
+public:
+    GamepadsGtk(unsigned length);
+
+    void registerDevice(String deviceFile);
+    void unregisterDevice(String deviceFile);
+
+    void updateGamepadList(GamepadList*);
+
+private:
+    ~GamepadsGtk();
+    static void onUEventCallback(GUdevClient*, gchar* action, GUdevDevice*, gpointer data);
+    static gboolean isGamepadDevice(GUdevDevice*);
+
+    Vector<OwnPtr<GamepadDeviceGtk> > m_slots;
+    HashMap<String, GamepadDeviceGtk*> m_deviceMap;
+
+    GRefPtr<GUdevClient> m_gudevClient;
+};
+
+GamepadsGtk::GamepadsGtk(unsigned length)
+    : m_slots(length)
+{
+    static const char* subsystems[] = { "input", 0 };
+    m_gudevClient = adoptGRef(g_udev_client_new(subsystems));
+    g_signal_connect(m_gudevClient.get(), "uevent", G_CALLBACK(onUEventCallback), this);
+
+    GOwnPtr<GList> devicesList(g_udev_client_query_by_subsystem(m_gudevClient.get(), subsystems[0]));
+    for (GList* listItem = devicesList.get(); listItem; listItem = g_list_next(listItem)) {
+        GUdevDevice* device = G_UDEV_DEVICE(listItem->data);
+        String deviceFile = String::fromUTF8(g_udev_device_get_device_file(device));
+        if (isGamepadDevice(device))
+            registerDevice(deviceFile);
+        g_object_unref(device);
+    }
+}
+
+GamepadsGtk::~GamepadsGtk()
+{
+    g_signal_handlers_disconnect_matched(m_gudevClient.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+}
+
+void GamepadsGtk::registerDevice(String deviceFile)
+{
+    ASSERT(!m_deviceMap.contains(deviceFile));
+
+    for (unsigned index = 0; index < m_slots.size(); index++) {
+        if (!m_slots[index]) {
+            m_slots[index] = GamepadDeviceGtk::create(deviceFile);
+            m_deviceMap.add(deviceFile, m_slots[index].get());
+            break;
+        }
+    }
+}
+
+void GamepadsGtk::unregisterDevice(String deviceFile)
+{
+    ASSERT(m_deviceMap.contains(deviceFile));
+
+    GamepadDeviceGtk* gamepadDevice = m_deviceMap.take(deviceFile);
+    unsigned index = m_slots.find(gamepadDevice);
+    ASSERT(index != notFound);
+
+    m_slots[index].clear();
+}
+
+void GamepadsGtk::updateGamepadList(GamepadList* into)
+{
+    ASSERT(m_slots.size() == into->length());
+
+    for (unsigned i = 0; i < m_slots.size(); i++) {
+        if (m_slots[i].get() && m_slots[i]->connected()) {
+            GamepadDeviceGtk* gamepadDevice = m_slots[i].get();
+            RefPtr<Gamepad> gamepad = into->item(i);
+            if (!gamepad)
+                gamepad = Gamepad::create();
+
+            gamepad->index(i);
+            gamepad->id(gamepadDevice->id());
+            gamepad->timestamp(gamepadDevice->timestamp());
+            gamepad->axes(gamepadDevice->axesCount(), gamepadDevice->axesData());
+            gamepad->buttons(gamepadDevice->buttonsCount(), gamepadDevice->buttonsData());
+
+            into->set(i, gamepad);
+        } else
+            into->set(i, 0);
+    }
+}
+
+void GamepadsGtk::onUEventCallback(GUdevClient* udevClient, gchar* action, GUdevDevice* device, gpointer data)
+{
+    if (!isGamepadDevice(device))
+        return;
+
+    GamepadsGtk* gamepadsGtk = reinterpret_cast<GamepadsGtk*>(data);
+    String deviceFile = String::fromUTF8(g_udev_device_get_device_file(device));
+
+    if (!g_strcmp0(action, "add"))
+        gamepadsGtk->registerDevice(deviceFile);
+    else if (!g_strcmp0(action, "remove"))
+        gamepadsGtk->unregisterDevice(deviceFile);
+}
+
+gboolean GamepadsGtk::isGamepadDevice(GUdevDevice* device)
+{
+    const gchar* deviceFile = g_udev_device_get_device_file(device);
+    const gchar* sysfsPath = g_udev_device_get_sysfs_path(device);
+    if (!deviceFile || !sysfsPath)
+        return FALSE;
+
+    if (!g_udev_device_has_property(device, "ID_INPUT") || !g_udev_device_has_property(device, "ID_INPUT_JOYSTICK"))
+        return FALSE;
+
+    return g_str_has_prefix(deviceFile, "/dev/input/js");
+}
+
+void sampleGamepads(GamepadList* into)
+{
+    DEFINE_STATIC_LOCAL(GamepadsGtk, gamepadsGtk, (into->length()));
+    gamepadsGtk.updateGamepadList(into);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebCore/platform/linux/GamepadDeviceLinux.cpp b/Source/WebCore/platform/linux/GamepadDeviceLinux.cpp
new file mode 100644 (file)
index 0000000..c25bc1b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
+ *
+ * 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 "GamepadDeviceLinux.h"
+
+#if ENABLE(GAMEPAD)
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+GamepadDeviceLinux::GamepadDeviceLinux(String deviceFile)
+    : m_fileDescriptor(-1)
+    , m_connected(false)
+    , m_lastTimestamp(0)
+{
+    // FIXME: Log errors when returning early.
+    m_fileDescriptor = open(deviceFile.utf8().data(), O_RDONLY | O_NONBLOCK);
+    if (m_fileDescriptor == -1)
+        return;
+
+    char deviceName[1024];
+    if (ioctl(m_fileDescriptor, JSIOCGNAME(sizeof(deviceName)), deviceName) < 0)
+        return;
+    m_deviceName = String(deviceName).simplifyWhiteSpace();
+
+    uint8_t numberOfAxes;
+    uint8_t numberOfButtons;
+    if (ioctl(m_fileDescriptor, JSIOCGAXES, &numberOfAxes) < 0 || ioctl(m_fileDescriptor, JSIOCGBUTTONS, &numberOfButtons) < 0)
+        return;
+    m_axes.fill(0.0, numberOfAxes);
+    m_buttons.fill(0.0, numberOfButtons);
+}
+
+GamepadDeviceLinux::~GamepadDeviceLinux()
+{
+    if (m_fileDescriptor != -1)
+        close(m_fileDescriptor);
+}
+
+void GamepadDeviceLinux::updateForEvent(struct js_event event)
+{
+    if (!(event.type & JS_EVENT_AXIS || event.type & JS_EVENT_BUTTON))
+        return;
+
+    // Mark the device as connected only if it is not yet connected, the event is not an initialization
+    // and the value is not 0 (indicating a genuine interaction with the device).
+    if (!m_connected && !(event.type & JS_EVENT_INIT) && event.value)
+        m_connected = true;
+
+    if (event.type & JS_EVENT_AXIS)
+        m_axes[event.number] = normalizeAxisValue(event.value);
+    else if (event.type & JS_EVENT_BUTTON)
+        m_buttons[event.number] = normalizeButtonValue(event.value);
+
+    m_lastTimestamp = event.time;
+}
+
+float GamepadDeviceLinux::normalizeAxisValue(short value)
+{
+    // Normalize from range [-32767, 32767] into range [-1.0, 1.0]
+    return value / 32767.0f;
+}
+
+float GamepadDeviceLinux::normalizeButtonValue(short value)
+{
+    // Normalize from range [0, 1] into range [0.0, 1.0]
+    return value / 1.0f;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
diff --git a/Source/WebCore/platform/linux/GamepadDeviceLinux.h b/Source/WebCore/platform/linux/GamepadDeviceLinux.h
new file mode 100644 (file)
index 0000000..d485e83
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef GamepadDeviceLinux_h
+#define GamepadDeviceLinux_h
+
+#if ENABLE(GAMEPAD)
+
+#include <linux/joystick.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class GamepadDeviceLinux {
+public:
+    bool connected() { return m_connected; };
+
+    String id() { return m_deviceName; }
+    unsigned long long timestamp() { return m_lastTimestamp; }
+
+    unsigned axesCount() { return m_axes.size(); }
+    float* axesData() { return m_axes.data(); }
+
+    unsigned buttonsCount() { return m_buttons.size(); }
+    float* buttonsData() { return m_buttons.data(); }
+
+protected:
+    GamepadDeviceLinux(String deviceFile);
+    ~GamepadDeviceLinux();
+
+    void updateForEvent(struct js_event);
+    int m_fileDescriptor;
+
+private:
+    float normalizeAxisValue(short value);
+    float normalizeButtonValue(short value);
+
+    bool m_connected;
+    String m_deviceName;
+    unsigned long long m_lastTimestamp;
+
+    Vector<float> m_axes;
+    Vector<float> m_buttons;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(GAMEPAD)
+
+#endif // GamepadDeviceLinux_h
index f2478d5..8035723 100644 (file)
@@ -1,3 +1,15 @@
+2012-06-27  Zan Dobersek  <zandobersek@gmail.com>
+
+        [Gtk] Add support for the Gamepad API
+        https://bugs.webkit.org/show_bug.cgi?id=87503
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add the Gamepad feature dependencies libraries to the LIBADD
+        list for the libwebkitgtk library.
+
+        * GNUmakefile.am:
+
 2012-06-25  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Update NEWS and configure.ac for 1.9.4 release
index 12ee765..db3afad 100644 (file)
@@ -87,6 +87,7 @@ libwebkitgtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIBA
        $(ENCHANT_LIBS) \
        $(FREETYPE_LIBS) \
        $(GAIL_LIBS) \
+       $(GAMEPAD_LIBS) \
        $(GEOCLUE_LIBS) \
        $(GLIB_LIBS) \
        $(GSTREAMER_LIBS) \
index d92c029..c41b41d 100644 (file)
@@ -1,3 +1,15 @@
+2012-06-27  Zan Dobersek  <zandobersek@gmail.com>
+
+        [Gtk] Add support for the Gamepad API
+        https://bugs.webkit.org/show_bug.cgi?id=87503
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add the Gamepad feature dependencies libraries to the LIBADD
+        list for the libwebkitgtk2 library.
+
+        * GNUmakefile.am:
+
 2012-06-26  Simon Hausmann  <simon.hausmann@nokia.com>
 
         [Qt] Avoid use of deprecated Qt API
index 016d681..15a69f9 100644 (file)
@@ -160,6 +160,7 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIB
        $(COVERAGE_LDFLAGS) \
        $(ENCHANT_LIBS) \
        $(GAIL_LIBS) \
+       $(GAMEPAD_LIBS) \
        $(GEOCLUE_LIBS) \
        $(GLIB_LIBS) \
        $(GSTREAMER_LIBS) \
index f7d4191..d777ee3 100644 (file)
@@ -1,3 +1,14 @@
+2012-06-27  Zan Dobersek  <zandobersek@gmail.com>
+
+        [Gtk] Add support for the Gamepad API
+        https://bugs.webkit.org/show_bug.cgi?id=87503
+
+        Reviewed by Carlos Garcia Campos.
+
+        Enable the gamepad support for the GTK port.
+
+        * Scripts/webkitperl/FeatureList.pm:
+
 2012-06-27  Ryosuke Niwa  <rniwa@webkit.org>
 
         Fix gcc build after r121302
index 0f033ac..888db38 100644 (file)
@@ -214,7 +214,7 @@ my @features = (
       define => "ENABLE_FULLSCREEN_API", default => (isAppleMacWebKit() || isEfl() || isGtk() || isBlackBerry() || isQt()), value => \$fullscreenAPISupport },
 
     { option => "gamepad", desc => "Toggle Gamepad support",
-      define => "ENABLE_GAMEPAD", default => 0, value => \$gamepadSupport },
+      define => "ENABLE_GAMEPAD", default => isGtk(), value => \$gamepadSupport },
 
     { option => "geolocation", desc => "Toggle Geolocation support",
       define => "ENABLE_GEOLOCATION", default => (isAppleWebKit() || isGtk() || isBlackBerry()), value => \$geolocationSupport },
index e6cb220..e9ccfff 100644 (file)
@@ -653,6 +653,11 @@ AC_ARG_ENABLE(gamepad,
               [],[enable_gamepad="no"])
 AC_MSG_RESULT([$enable_gamepad])
 
+if test "$enable_gamepad" = "yes" && test "$os_linux" = no; then
+   AC_MSG_WARN([Gamepad support is only available on Linux. Disabling Gamepad support.])
+   enable_gamepad=no;
+fi
+
 # check whether to build with data transfer items support
 AC_MSG_CHECKING([whether to enable HTML5 data transfer items support])
 AC_ARG_ENABLE(data_transfer_items,
@@ -1276,6 +1281,13 @@ if test "$enable_webkit2" = "yes"; then
    AC_SUBST([ATSPI2_LIBS])
 fi
 
+if test "$enable_gamepad" = "yes"; then
+   PKG_CHECK_MODULES([GAMEPAD], [gio-unix-2.0 gudev-1.0])
+
+   AC_SUBST(GAMEPAD_CFLAGS)
+   AC_SUBST(GAMEPAD_LIBS)
+fi
+
 # check for code coverage support
 if test "$enable_coverage" = "yes"; then
    COVERAGE_CFLAGS="-MD"