[clutter/clutter-1.16] evdev: switch to libevdev for fetching the events
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter/clutter-1.16] evdev: switch to libevdev for fetching the events
- Date: Mon, 9 Sep 2013 11:25:07 +0000 (UTC)
commit cd1749a2a55b4a0d8ba016d00265686909b4bbd9
Author: Giovanni Campagna <gcampagn redhat com>
Date: Fri Sep 6 16:03:29 2013 +0200
evdev: switch to libevdev for fetching the events
libevdev is a library that wraps the evdev subsystem, with
the ability to synchronize the state after a SYN_DROPPED event
from the kernel.
https://bugzilla.gnome.org/show_bug.cgi?id=706494
README.in | 5 +
clutter/evdev/clutter-device-manager-evdev.c | 297 +++++++++++++++-----------
configure.ac | 2 +-
3 files changed, 180 insertions(+), 124 deletions(-)
---
diff --git a/README.in b/README.in
index b8460c7..c059e68 100644
--- a/README.in
+++ b/README.in
@@ -38,6 +38,11 @@ When building the CEx100 backend, Clutter also depends on:
• libgdl
+When building the evdev input backend, Clutter also depends on:
+
+ • xkbcommon
+ • libevdev
+
If you are building the API reference you will also need:
• GTK-Doc ≥ @GTK_DOC_REQ_VERSION@
diff --git a/clutter/evdev/clutter-device-manager-evdev.c b/clutter/evdev/clutter-device-manager-evdev.c
index dd6b5f6..5ca7ffb 100644
--- a/clutter/evdev/clutter-device-manager-evdev.c
+++ b/clutter/evdev/clutter-device-manager-evdev.c
@@ -35,6 +35,7 @@
#include <glib.h>
#include <gudev/gudev.h>
+#include <libevdev/libevdev.h>
#include "clutter-backend.h"
#include "clutter-debug.h"
@@ -124,6 +125,7 @@ struct _ClutterEventSource
ClutterInputDeviceEvdev *device; /* back pointer to the slave evdev device */
GPollFD event_poll_fd; /* file descriptor of the /dev node */
+ struct libevdev *dev;
};
static gboolean
@@ -411,6 +413,143 @@ notify_button (ClutterEventSource *source,
queue_event (event);
}
+static void
+dispatch_one_event (ClutterEventSource *source,
+ struct input_event *e,
+ int *dx,
+ int *dy)
+{
+ guint32 _time;
+
+ _time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
+
+ switch (e->type)
+ {
+ case EV_KEY:
+ /* don't repeat mouse buttons */
+ if (e->code >= BTN_MOUSE && e->code < KEY_OK)
+ if (e->value == AUTOREPEAT_VALUE)
+ return;
+
+ switch (e->code)
+ {
+ case BTN_TOUCH:
+ case BTN_TOOL_PEN:
+ case BTN_TOOL_RUBBER:
+ case BTN_TOOL_BRUSH:
+ case BTN_TOOL_PENCIL:
+ case BTN_TOOL_AIRBRUSH:
+ case BTN_TOOL_FINGER:
+ case BTN_TOOL_MOUSE:
+ case BTN_TOOL_LENS:
+ break;
+
+ case BTN_LEFT:
+ case BTN_RIGHT:
+ case BTN_MIDDLE:
+ case BTN_SIDE:
+ case BTN_EXTRA:
+ case BTN_FORWARD:
+ case BTN_BACK:
+ case BTN_TASK:
+ notify_button(source, _time, e->code, e->value);
+ break;
+
+ default:
+ notify_key (source, _time, e->code, e->value);
+ break;
+ }
+ break;
+
+ case EV_SYN:
+ /* Nothing to do here */
+ break;
+
+ case EV_MSC:
+ /* Nothing to do here */
+ break;
+
+ case EV_REL:
+ /* compress the EV_REL events in dx/dy */
+ switch (e->code)
+ {
+ case REL_X:
+ *dx += e->value;
+ break;
+ case REL_Y:
+ *dy += e->value;
+ break;
+
+ /* Note: we assume that REL_WHEEL is for *vertical* scroll wheels.
+ To implement horizontal scroll, we'll need a different enum
+ value.
+ */
+ case REL_WHEEL:
+ notify_scroll (source, _time, e->value);
+ break;
+ }
+ break;
+
+ case EV_ABS:
+ default:
+ g_warning ("Unhandled event of type %d", e->type);
+ break;
+ }
+}
+
+static void
+sync_source (ClutterEventSource *source)
+{
+ struct input_event ev;
+ int err;
+ int dx = 0, dy = 0;
+ const gchar *device_path;
+
+ /* We read a SYN_DROPPED, ignore it and sync the device */
+ err = libevdev_next_event (source->dev, LIBEVDEV_READ_SYNC, &ev);
+ while (err == 1)
+ {
+ dispatch_one_event (source, &ev, &dx, &dy);
+ err = libevdev_next_event (source->dev, LIBEVDEV_READ_SYNC, &ev);
+ }
+
+ if (err != -EAGAIN && CLUTTER_HAS_DEBUG (EVENT))
+ {
+ device_path = _clutter_input_device_evdev_get_device_path (source->device);
+
+ CLUTTER_NOTE (EVENT, "Could not sync device (%s).", device_path);
+ }
+
+ if (dx != 0 || dy != 0)
+ {
+ guint32 _time = ev.time.tv_sec * 1000 + ev.time.tv_usec / 1000;
+ notify_relative_motion (source, _time, dx, dy);
+ }
+}
+
+static void
+fail_source (ClutterEventSource *source,
+ int error)
+{
+ ClutterDeviceManager *manager;
+ ClutterInputDevice *device;
+ const gchar *device_path;
+
+ device = CLUTTER_INPUT_DEVICE (source->device);
+
+ if (CLUTTER_HAS_DEBUG (EVENT))
+ {
+ device_path = _clutter_input_device_evdev_get_device_path (source->device);
+
+ CLUTTER_NOTE (EVENT, "Could not read device (%s): %s. Removing.",
+ device_path, strerror (error));
+ }
+
+ /* remove the faulty device */
+ manager = clutter_device_manager_get_default ();
+ _clutter_device_manager_remove_device (manager, device);
+}
+
static gboolean
clutter_event_dispatch (GSource *g_source,
GSourceFunc callback,
@@ -418,11 +557,10 @@ clutter_event_dispatch (GSource *g_source,
{
ClutterEventSource *source = (ClutterEventSource *) g_source;
ClutterInputDevice *input_device = (ClutterInputDevice *) source->device;
- struct input_event ev[8];
+ struct input_event ev;
ClutterEvent *event;
- gint len, i, dx = 0, dy = 0;
- uint32_t _time;
ClutterStage *stage;
+ int err, dx = 0, dy = 0;
_clutter_threads_acquire_lock ();
@@ -430,125 +568,36 @@ clutter_event_dispatch (GSource *g_source,
/* Don't queue more events if we haven't finished handling the previous batch
*/
- if (!clutter_events_pending ())
+ if (clutter_events_pending ())
+ goto queue_event;
+
+ err = libevdev_next_event (source->dev, LIBEVDEV_READ_NORMAL, &ev);
+ while (err != -EAGAIN)
+ {
+ if (err == 1)
+ sync_source (source);
+ else if (err == 0)
+ dispatch_one_event (source, &ev, &dx, &dy);
+ else
+ {
+ fail_source (source, -err);
+ goto out;
+ }
+
+ err = libevdev_next_event (source->dev, LIBEVDEV_READ_NORMAL, &ev);
+ }
+
+ if (dx != 0 || dy != 0)
{
- len = read (source->event_poll_fd.fd, &ev, sizeof (ev));
- if (len < 0 || len % sizeof (ev[0]) != 0)
- {
- if (errno != EAGAIN)
- {
- ClutterDeviceManager *manager;
- ClutterInputDevice *device;
- const gchar *device_path;
-
- device = CLUTTER_INPUT_DEVICE (source->device);
-
- if (CLUTTER_HAS_DEBUG (EVENT))
- {
- device_path =
- _clutter_input_device_evdev_get_device_path (source->device);
-
- CLUTTER_NOTE (EVENT, "Could not read device (%s), removing.",
- device_path);
- }
-
- /* remove the faulty device */
- manager = clutter_device_manager_get_default ();
- _clutter_device_manager_remove_device (manager, device);
-
- }
- goto out;
- }
-
- /* Drop events if we don't have any stage to forward them to */
- if (!stage)
- goto out;
-
- for (i = 0; i < len / sizeof (ev[0]); i++)
- {
- struct input_event *e = &ev[i];
-
- _time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
-
- switch (e->type)
- {
- case EV_KEY:
-
- /* don't repeat mouse buttons */
- if (e->code >= BTN_MOUSE && e->code < KEY_OK)
- if (e->value == AUTOREPEAT_VALUE)
- continue;
-
- switch (e->code)
- {
- case BTN_TOUCH:
- case BTN_TOOL_PEN:
- case BTN_TOOL_RUBBER:
- case BTN_TOOL_BRUSH:
- case BTN_TOOL_PENCIL:
- case BTN_TOOL_AIRBRUSH:
- case BTN_TOOL_FINGER:
- case BTN_TOOL_MOUSE:
- case BTN_TOOL_LENS:
- break;
-
- case BTN_LEFT:
- case BTN_RIGHT:
- case BTN_MIDDLE:
- case BTN_SIDE:
- case BTN_EXTRA:
- case BTN_FORWARD:
- case BTN_BACK:
- case BTN_TASK:
- notify_button(source, _time, e->code, e->value);
- break;
-
- default:
- notify_key (source, _time, e->code, e->value);
- break;
- }
- break;
-
- case EV_SYN:
- /* Nothing to do here? */
- break;
-
- case EV_MSC:
- /* Nothing to do here? */
- break;
-
- case EV_REL:
- /* compress the EV_REL events in dx/dy */
- switch (e->code)
- {
- case REL_X:
- dx += e->value;
- break;
- case REL_Y:
- dy += e->value;
- break;
-
- /* Note: we assume that REL_WHEEL is for *vertical* scroll wheels.
- To implement horizontal scroll, we'll need a different enum
- value.
- */
- case REL_WHEEL:
- notify_scroll (source, _time, e->value);
- break;
- }
- break;
-
- case EV_ABS:
- default:
- g_warning ("Unhandled event of type %d", e->type);
- break;
- }
- }
-
- if (dx != 0 || dy != 0)
- notify_relative_motion (source, _time, dx, dy);
+ guint32 _time = ev.time.tv_sec * 1000 + ev.time.tv_usec / 1000;
+ notify_relative_motion (source, _time, dx, dy);
}
+ queue_event:
+ /* Drop events if we don't have any stage to forward them to */
+ if (stage == NULL)
+ goto out;
+
/* Pop an event off the queue if any */
event = clutter_event_get ();
@@ -619,14 +668,15 @@ clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
}
}
+ /* Tell evdev to use the monotonic clock for its timestamps */
+ clkid = CLOCK_MONOTONIC;
+ ioctl (fd, EVIOCSCLOCKID, &clkid);
+
/* setup the source */
event_source->device = input_device;
event_source->event_poll_fd.fd = fd;
event_source->event_poll_fd.events = G_IO_IN;
-
- /* Tell evdev to use the monotonic clock for its timestamps */
- clkid = CLOCK_MONOTONIC;
- ioctl (fd, EVIOCSCLOCKID, &clkid);
+ libevdev_new_from_fd (fd, &event_source->dev);
/* and finally configure and attach the GSource */
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
@@ -650,6 +700,7 @@ clutter_event_source_free (ClutterEventSource *source)
/* ignore the return value of close, it's not like we can do something
* about it */
close (source->event_poll_fd.fd);
+ libevdev_free (source->dev);
g_source_destroy (g_source);
g_source_unref (g_source);
diff --git a/configure.ac b/configure.ac
index cd296c1..7bfd722 100644
--- a/configure.ac
+++ b/configure.ac
@@ -480,7 +480,7 @@ AS_IF([test "x$enable_evdev" = "xyes"],
AS_IF([test "x$have_evdev" = "xyes"],
[
CLUTTER_INPUT_BACKENDS="$CLUTTER_INPUT_BACKENDS evdev"
- BACKEND_PC_FILES="$BACKEND_PC_FILES gudev-1.0 xkbcommon"
+ BACKEND_PC_FILES="$BACKEND_PC_FILES gudev-1.0 libevdev xkbcommon"
experimental_input_backend="yes"
AC_DEFINE([HAVE_EVDEV], [1], [Have evdev support for input handling])
SUPPORT_EVDEV=1
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]