This backend is a event backend that can be enabled for EGL (for now).
It uses udev (gudev) to query input devices on a linux system, listens to
keyboard events from input devices and xkbcommon to translate raw key
codes into key keysyms.
This commit only supports key events, more to follow.
egl_tslib_c = $(srcdir)/egl/clutter-event-tslib.c
+evdev_c_priv = \
+ $(srcdir)/evdev/clutter-xkb-utils.c \
+ $(srcdir)/evdev/clutter-device-manager-evdev.c \
+ $(srcdir)/evdev/clutter-input-device-evdev.c \
+ $(srcdir)/evdev/clutter-event-evdev.c \
+ $(NULL)
+evdev_h_priv = \
+ $(srcdir)/evdev/clutter-xkb-utils.h \
+ $(srcdir)/evdev/clutter-device-manager-evdev.h \
+ $(srcdir)/evdev/clutter-input-device-evdev.h \
+ $(srcdir)/evdev/clutter-event-evdev.h \
+ $(NULL)
+
egl_cex_c_priv = $(srcdir)/egl/clutter-backend-cex100.c
egl_cex_h_priv = $(srcdir)/egl/clutter-backend-cex100.h
egl_cex_h = $(srcdir)/egl/clutter-cex100.h
if SUPPORT_EGL
+
if USE_TSLIB
egl_source_c_priv += $(egl_tslib_c)
endif # SUPPORT_TSLIB
+
+if SUPPORT_EVDEV
+egl_source_c_priv += $(evdev_c_priv)
+egl_source_h_priv += $(evdev_h_priv)
+endif # SUPPORT_EVDEV
+
if SUPPORT_CEX100
egl_source_c_priv += $(egl_cex_c_priv)
egl_source_h_priv += $(egl_cex_h_priv)
#define __CLUTTER_DEVICE_MANAGER_PRIVATE_H__
#include <clutter/clutter-device-manager.h>
+#include <clutter/clutter-event.h>
G_BEGIN_DECLS
* @CLUTTER_POINTER_DEVICE: A pointer device
* @CLUTTER_KEYBOARD_DEVICE: A keyboard device
* @CLUTTER_EXTENSION_DEVICE: A generic extension device
+ * @CLUTTER_JOYSTICK_DEVICE: A joystick device
+ * @CLUTTER_TABLET_DEVICE: A tablet device
+ * @CLUTTER_TOUCHPAD_DEVICE: A touchpad device
+ * @CLUTTER_TOUCHSCREEN_DEVICE: A touch screen device
* @CLUTTER_N_DEVICE_TYPES: The number of device types
*
* The types of input devices available.
CLUTTER_POINTER_DEVICE,
CLUTTER_KEYBOARD_DEVICE,
CLUTTER_EXTENSION_DEVICE,
+ CLUTTER_JOYSTICK_DEVICE,
+ CLUTTER_TABLET_DEVICE,
+ CLUTTER_TOUCHPAD_DEVICE,
+ CLUTTER_TOUCHSCREEN_DEVICE,
CLUTTER_N_DEVICE_TYPES
} ClutterInputDeviceType;
#include "clutter-stage-egl.h"
#include "clutter-egl.h"
+#ifdef HAVE_EVDEV
+#include "clutter-device-manager-evdev.h"
+#include "clutter-event-evdev.h"
+#endif
+
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-main.h"
_clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage);
}
-#ifdef HAVE_TSLIB
+static ClutterDeviceManager *
+clutter_backend_egl_get_device_manager (ClutterBackend *backend)
+{
+ ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
+
+ if (G_UNLIKELY (backend_egl->device_manager == NULL))
+ {
+#ifdef HAVE_EVDEV
+ backend_egl->device_manager =
+ g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_EVDEV,
+ "backend", backend_egl,
+ NULL);
+#endif
+ }
+
+ return backend_egl->device_manager;
+}
+
static void
clutter_backend_egl_init_events (ClutterBackend *backend)
{
+#ifdef HAVE_TSLIB
/* XXX: This should be renamed to _clutter_events_tslib_init */
_clutter_events_egl_init (CLUTTER_BACKEND_EGL (backend));
-}
#endif
+#ifdef HAVE_EVDEV
+ _clutter_events_evdev_init (CLUTTER_BACKEND (backend));
+#endif
+}
static void
clutter_backend_egl_finalize (GObject *gobject)
gobject_class->dispose = clutter_backend_egl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize;
- backend_class->pre_parse = clutter_backend_egl_pre_parse;
- backend_class->post_parse = clutter_backend_egl_post_parse;
- backend_class->get_features = clutter_backend_egl_get_features;
-#ifdef HAVE_TSLIB
- backend_class->init_events = clutter_backend_egl_init_events;
-#endif
- backend_class->create_stage = clutter_backend_egl_create_stage;
- backend_class->create_context = clutter_backend_egl_create_context;
- backend_class->ensure_context = clutter_backend_egl_ensure_context;
- backend_class->redraw = clutter_backend_egl_redraw;
+ backend_class->pre_parse = clutter_backend_egl_pre_parse;
+ backend_class->post_parse = clutter_backend_egl_post_parse;
+ backend_class->get_features = clutter_backend_egl_get_features;
+ backend_class->get_device_manager = clutter_backend_egl_get_device_manager;
+ backend_class->init_events = clutter_backend_egl_init_events;
+ backend_class->create_stage = clutter_backend_egl_create_stage;
+ backend_class->create_context = clutter_backend_egl_create_context;
+ backend_class->ensure_context = clutter_backend_egl_ensure_context;
+ backend_class->redraw = clutter_backend_egl_redraw;
#ifdef COGL_HAS_XLIB_SUPPORT
backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info;
#include <glib-object.h>
#include <clutter/clutter-event.h>
+#include <clutter/clutter-backend.h>
+#include <clutter/clutter-device-manager.h>
+
#ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h>
#include <X11/Xatom.h>
/* main stage singleton */
ClutterStageWindow *stage;
+ /* device manager (ie evdev) */
+ ClutterDeviceManager *device_manager;
+
/* event source */
GSource *event_source;
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <linux/input.h>
+
+#include <gudev/gudev.h>
+
+#include "clutter-backend.h"
+#include "clutter-debug.h"
+#include "clutter-device-manager.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-input-device-evdev.h"
+#include "clutter-private.h"
+
+#include "clutter-device-manager-evdev.h"
+
+#define CLUTTER_DEVICE_MANAGER_EVDEV_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, \
+ ClutterDeviceManagerEvdevPrivate))
+
+G_DEFINE_TYPE (ClutterDeviceManagerEvdev,
+ clutter_device_manager_evdev,
+ CLUTTER_TYPE_DEVICE_MANAGER);
+
+struct _ClutterDeviceManagerEvdevPrivate
+{
+ GUdevClient *udev_client;
+
+ GSList *devices;
+
+ ClutterInputDevice *core_pointer;
+ ClutterInputDevice *core_keyboard;
+};
+
+static const gchar *subsystems[] = { "input", NULL };
+
+static void
+evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev,
+ GUdevDevice *udev_device)
+{
+ ClutterDeviceManager *manager = (ClutterDeviceManager *) manager_evdev;
+ ClutterInputDeviceType type = CLUTTER_EXTENSION_DEVICE;
+ ClutterInputDevice *device;
+ const gchar *dev_file;
+ const gchar * const *keys;
+ guint i;
+
+ dev_file = g_udev_device_get_device_file (udev_device);
+
+ if (g_udev_device_get_property (udev_device, "ID_INPUT") == NULL)
+ {
+ CLUTTER_NOTE (EVENT, "Ignoring device %s without ID_INPUT set", dev_file);
+ return;
+ }
+
+ keys = g_udev_device_get_property_keys (udev_device);
+ for (i = 0; keys[i]; i++)
+ {
+ /* Clutter assumes that device types are exclusive in the
+ * ClutterInputDevice API */
+ if (strcmp (keys[i], "ID_INPUT_KEY") == 0)
+ type = CLUTTER_KEYBOARD_DEVICE;
+ else if (strcmp (keys[i], "ID_INPUT_MOUSE") == 0)
+ type = CLUTTER_POINTER_DEVICE;
+ else if (strcmp (keys[i], "ID_INPUT_JOYSTICK") == 0)
+ type = CLUTTER_JOYSTICK_DEVICE;
+ else if (strcmp (keys[i], "ID_INPUT_TABLET") == 0)
+ type = CLUTTER_TABLET_DEVICE;
+ else if (strcmp (keys[i], "ID_INPUT_TOUCHPAD") == 0)
+ type = CLUTTER_TOUCHPAD_DEVICE;
+ else if (strcmp (keys[i], "ID_INPUT_TOUCHSCREEN") == 0)
+ type = CLUTTER_TOUCHSCREEN_DEVICE;
+ }
+
+ device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV,
+ "id", 0,
+ "name", "Evdev device", /* FIXME */
+ "device-type", type,
+ "sysfs-path", sysfs_path,
+ "device-path", device_file,
+ NULL);
+ _clutter_device_manager_add_device (manager, device);
+
+ CLUTTER_NOTE (EVENT, "Added device %s, type %d", dev_file, type);
+}
+
+/*
+ * ClutterDeviceManager implementation
+ */
+
+static void
+clutter_device_manager_evdev_add_device (ClutterDeviceManager *manager,
+ ClutterInputDevice *device)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+ ClutterInputDeviceType device_type;
+ gboolean is_pointer, is_keyboard;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
+ priv = manager_evdev->priv;
+
+ device_type = clutter_input_device_get_device_type (device);
+ is_pointer = device_type == CLUTTER_POINTER_DEVICE;
+ is_keyboard = device_type == CLUTTER_KEYBOARD_DEVICE;
+
+ priv->devices = g_slist_prepend (priv->devices, device);
+
+ if (is_pointer && priv->core_pointer == NULL)
+ priv->core_pointer = device;
+
+ if (is_keyboard && priv->core_keyboard == NULL)
+ priv->core_keyboard = device;
+}
+
+static void
+clutter_device_manager_evdev_remove_device (ClutterDeviceManager *manager,
+ ClutterInputDevice *device)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
+ priv = manager_evdev->priv;
+
+ priv->devices = g_slist_remove (priv->devices, device);
+}
+
+static const GSList *
+clutter_device_manager_evdev_get_devices (ClutterDeviceManager *manager)
+{
+ return CLUTTER_DEVICE_MANAGER_EVDEV (manager)->priv->devices;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_evdev_get_core_device (ClutterDeviceManager *manager,
+ ClutterInputDeviceType type)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
+ priv = manager_evdev->priv;
+
+ switch (type)
+ {
+ case CLUTTER_POINTER_DEVICE:
+ return priv->core_pointer;
+
+ case CLUTTER_KEYBOARD_DEVICE:
+ return priv->core_keyboard;
+
+ case CLUTTER_EXTENSION_DEVICE:
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_evdev_get_device (ClutterDeviceManager *manager,
+ gint id)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+ GSList *l;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
+ priv = manager_evdev->priv;
+
+ for (l = priv->devices; l; l = l->next)
+ {
+ ClutterInputDevice *device = l->data;
+
+ if (clutter_input_device_get_device_id (device) == id)
+ return device;
+ }
+
+ return NULL;
+}
+
+/*
+ * GObject implementation
+ */
+
+static void
+clutter_device_manager_evdev_constructed (GObject *gobject)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+ GList *devices, *l;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (gobject);
+ priv = manager_evdev->priv;
+
+ priv->udev_client = g_udev_client_new (subsystems);
+
+ devices = g_udev_client_query_by_subsystem (priv->udev_client, subsystems[0]);
+ for (l = devices; l; l = g_list_next (l))
+ {
+ GUdevDevice *device = l->data;
+
+ evdev_add_device (manager_evdev, device);
+ g_object_unref (device);
+ }
+ g_list_free (devices);
+
+ /* subcribe for events on input devices */
+ g_signal_connect (priv->udev_client, "uevent",
+ G_CALLBACK (on_uevent), manager_evdev);
+}
+
+static void
+clutter_device_manager_evdev_finalize (GObject *object)
+{
+ ClutterDeviceManagerEvdev *manager_evdev;
+ ClutterDeviceManagerEvdevPrivate *priv;
+
+ manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (object);
+ priv = manager_evdev->priv;
+
+ g_object_unref (priv->udev_client);
+
+ G_OBJECT_CLASS (clutter_device_manager_evdev_parent_class)->finalize (object);
+}
+
+static void
+clutter_device_manager_evdev_class_init (ClutterDeviceManagerEvdevClass *klass)
+{
+ ClutterDeviceManagerClass *manager_class;
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ g_type_class_add_private (klass, sizeof (ClutterDeviceManagerEvdevPrivate));
+
+ gobject_class->constructed = clutter_device_manager_evdev_constructed;
+ gobject_class->finalize = clutter_device_manager_evdev_finalize;
+
+ manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
+ manager_class->add_device = clutter_device_manager_evdev_add_device;
+ manager_class->remove_device = clutter_device_manager_evdev_remove_device;
+ manager_class->get_devices = clutter_device_manager_evdev_get_devices;
+ manager_class->get_core_device = clutter_device_manager_evdev_get_core_device;
+ manager_class->get_device = clutter_device_manager_evdev_get_device;
+}
+
+static void
+clutter_device_manager_evdev_init (ClutterDeviceManagerEvdev *self)
+{
+ self->priv = CLUTTER_DEVICE_MANAGER_EVDEV_GET_PRIVATE (self);
+}
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __CLUTTER_DEVICE_MANAGER_EVDEV_H__
+#define __CLUTTER_DEVICE_MANAGER_EVDEV_H__
+
+#include <clutter/clutter-device-manager.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DEVICE_MANAGER_EVDEV (clutter_device_manager_evdev_get_type ())
+#define CLUTTER_DEVICE_MANAGER_EVDEV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdev))
+#define CLUTTER_IS_DEVICE_MANAGER_EVDEV(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV))
+#define CLUTTER_DEVICE_MANAGER_EVDEV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdevClass))
+#define CLUTTER_IS_DEVICE_MANAGER_EVDEV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV))
+#define CLUTTER_DEVICE_MANAGER_EVDEV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdevClass))
+
+typedef struct _ClutterDeviceManagerEvdev ClutterDeviceManagerEvdev;
+typedef struct _ClutterDeviceManagerEvdevClass ClutterDeviceManagerEvdevClass;
+typedef struct _ClutterDeviceManagerEvdevPrivate ClutterDeviceManagerEvdevPrivate;
+
+struct _ClutterDeviceManagerEvdev
+{
+ ClutterDeviceManager parent_instance;
+
+ ClutterDeviceManagerEvdevPrivate *priv;
+};
+
+struct _ClutterDeviceManagerEvdevClass
+{
+ ClutterDeviceManagerClass parent_class;
+};
+
+GType clutter_device_manager_evdev_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEVICE_MANAGER_EVDEV_H__ */
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2006-2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <linux/input.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <gudev/gudev.h>
+
+#include "clutter-backend.h"
+#include "clutter-debug.h"
+#include "clutter-device-manager.h"
+#include "clutter-event.h"
+#include "clutter-input-device-evdev.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+#include "clutter-xkb-utils.h"
+
+/* List of all the event sources */
+static GSList *event_sources = NULL;
+
+const char *option_xkb_layout = "us";
+const char *option_xkb_variant = "";
+const char *option_xkb_options = "";
+
+/*
+ * ClutterEventSource for reading input devices
+ */
+
+typedef struct _ClutterEventSource ClutterEventSource;
+
+struct _ClutterEventSource
+{
+ GSource source;
+
+ ClutterInputDeviceEvdev *device; /* back pointer to the evdev device */
+ GPollFD event_poll_fd; /* file descriptor of the /dev node */
+ struct xkb_desc *xkb; /* compiled xkb keymap */
+ uint32_t modifier_state; /* remember the modifier state */
+};
+
+static gboolean
+clutter_event_prepare (GSource *source,
+ gint *timeout)
+{
+ gboolean retval;
+
+ clutter_threads_enter ();
+
+ *timeout = -1;
+ retval = clutter_events_pending ();
+
+ clutter_threads_leave ();
+
+ return retval;
+}
+
+static gboolean
+clutter_event_check (GSource *source)
+{
+ ClutterEventSource *event_source = (ClutterEventSource *) source;
+ gboolean retval;
+
+ clutter_threads_enter ();
+
+ retval = ((event_source->event_poll_fd.revents & G_IO_IN) ||
+ clutter_events_pending ());
+
+ clutter_threads_leave ();
+
+ return retval;
+}
+
+static gboolean
+clutter_event_dispatch (GSource *g_source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ ClutterEventSource *source = (ClutterEventSource *) g_source;
+ ClutterInputDevice *input_device = (ClutterInputDevice *) source->device;
+ ClutterMainContext *clutter_context;
+ struct input_event ev[8];
+ ClutterEvent *event = NULL;
+ ClutterStage *stage;
+ gint len, i;
+
+ clutter_threads_enter ();
+
+ clutter_context = _clutter_context_get_default ();
+ stage = CLUTTER_STAGE (clutter_stage_get_default ());
+
+ /* Don't queue more events if we haven't finished handling the previous batch
+ */
+ if (!clutter_events_pending ())
+ {
+ len = read (source->event_poll_fd.fd, &ev, sizeof (ev));
+ if (len < 0 || len % sizeof (ev[0]) != 0)
+ {
+ if (errno != EAGAIN)
+ {
+ g_warning ("Could not read device (%d)", errno);
+ }
+ goto out;
+ }
+
+ for (i = 0; i < len / sizeof (ev[0]); i++)
+ {
+ struct input_event *e = &ev[i];
+ uint32_t _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 == 2)
+ continue;
+
+ event =
+ _clutter_key_event_new_from_evdev (input_device,
+ stage,
+ source->xkb,
+ _time, e->code, e->value,
+ &source->modifier_state);
+
+ break;
+ case EV_SYN:
+ /* Nothing to do here? */
+ break;
+ case EV_MSC:
+ /* Nothing to do here? */
+ break;
+ case EV_ABS:
+ case EV_REL:
+ default:
+ g_warning ("Unhandled event of type %d", e->type);
+ break;
+ }
+
+ if (event)
+ {
+ g_queue_push_head (clutter_context->events_queue, event);
+ event = NULL;
+ }
+ }
+ }
+
+ /* Pop an event off the queue if any */
+ event = clutter_event_get ();
+
+ if (event)
+ {
+ /* forward the event into clutter for emission etc. */
+ clutter_do_event (event);
+ clutter_event_free (event);
+ }
+
+out:
+ clutter_threads_leave ();
+
+ return TRUE;
+}
+static GSourceFuncs event_funcs = {
+ clutter_event_prepare,
+ clutter_event_check,
+ clutter_event_dispatch,
+ NULL
+};
+
+static GSource *
+clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
+{
+ GSource *source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
+ ClutterEventSource *event_source = (ClutterEventSource *) source;
+ const gchar *node_path;
+ gint fd;
+
+ /* grab the udev input device node and open it */
+ node_path = _clutter_input_device_evdev_get_device_path (input_device);
+
+ CLUTTER_NOTE (EVENT, "Creating GSource for device %s", node_path);
+
+ fd = open (node_path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ {
+ g_warning ("Could not open device %s: %s", node_path, strerror (errno));
+ return NULL;
+ }
+
+ /* setup the source */
+ event_source->device = input_device;
+ event_source->event_poll_fd.fd = fd;
+ event_source->event_poll_fd.events = G_IO_IN;
+
+ /* create the xkb description */
+ event_source->xkb = _clutter_xkb_desc_new (NULL,
+ option_xkb_layout,
+ option_xkb_variant,
+ option_xkb_options);
+ if (G_UNLIKELY (event_source->xkb == NULL))
+ {
+ g_warning ("Could not compile keymap %s:%s:%s", option_xkb_layout,
+ option_xkb_variant, option_xkb_options);
+ close (fd);
+ g_source_unref (source);
+ return NULL;
+ }
+
+ /* and finally configure and attach the GSource */
+ g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
+ g_source_add_poll (source, &event_source->event_poll_fd);
+ g_source_set_can_recurse (source, TRUE);
+ g_source_attach (source, NULL);
+
+ return source;
+}
+
+static void
+clutter_event_source_free (ClutterEventSource *source)
+{
+ GSource *g_source = (GSource *) source;
+ const gchar *node_path;
+
+ node_path = _clutter_input_device_evdev_get_device_path (source->device);
+
+ CLUTTER_NOTE (EVENT, "Removing GSource for device %s", node_path);
+
+ /* ignore the return value of close, it's not like we can do something
+ * about it */
+ close (source->event_poll_fd.fd);
+
+ g_source_destroy (g_source);
+ g_source_unref (g_source);
+}
+
+static void
+_clutter_event_evdev_add_source (ClutterInputDeviceEvdev *input_device)
+{
+ GSource *source;
+
+ source = clutter_event_source_new (input_device);
+ if (G_LIKELY (source))
+ event_sources = g_slist_prepend (event_sources, source);
+}
+
+static void
+_clutter_event_evdev_remove_source (ClutterEventSource *source)
+{
+ clutter_event_source_free (source);
+ event_sources = g_slist_remove (event_sources, source);
+}
+
+void
+_clutter_events_evdev_init (ClutterBackend *backend)
+{
+ ClutterDeviceManager *device_manager;
+ GSList *devices, *l;
+
+ CLUTTER_NOTE (EVENT, "Initializing evdev backend");
+
+ /* Of course, we assume that the singleton will be a
+ * ClutterDeviceManagerEvdev */
+ device_manager = clutter_device_manager_get_default ();
+
+ devices = clutter_device_manager_list_devices (device_manager);
+ for (l = devices; l; l = g_slist_next (l))
+ {
+ ClutterInputDeviceEvdev *input_device = l->data;
+
+ _clutter_event_evdev_add_source (input_device);
+ }
+}
+
+void
+_clutter_events_evdev_uninit (ClutterBackend *backend)
+{
+ GSList *l;
+
+ for (l = event_sources; l; l = g_slist_next (l))
+ {
+ ClutterEventSource *source = l->data;
+
+ clutter_event_source_free (source);
+ }
+ g_slist_free (event_sources);
+}
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __CLUTTER_EVENT_EVDEV_H__
+#define __CLUTTER_EVENT_EVDEV_H__
+
+#include <glib.h>
+
+#include <clutter/clutter-backend.h>
+
+G_BEGIN_DECLS
+
+void _clutter_events_evdev_init (ClutterBackend *backend);
+void _clutter_events_evdev_uninit (ClutterBackend *backend);
+
+#endif /* __CLUTTER_EVENT_EVDEV_H__ */
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter/clutter-device-manager-private.h"
+#include "clutter-private.h"
+
+#include "clutter-input-device-evdev.h"
+
+typedef struct _ClutterInputDeviceClass ClutterInputDeviceEvdevClass;
+typedef struct _ClutterInputDeviceEvdevPrivate ClutterInputDeviceEvdevPrivate;
+
+#define INPUT_DEVICE_EVDEV_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, \
+ ClutterInputDeviceEvdevPrivate))
+
+enum
+{
+ PROP_0,
+
+ PROP_SYSFS_PATH,
+ PROP_DEVICE_PATH,
+
+ PROP_LAST
+};
+
+struct _ClutterInputDeviceEvdevPrivate
+{
+ gchar *sysfs_path;
+ gchar *device_path;
+};
+
+struct _ClutterInputDeviceEvdev
+{
+ ClutterInputDevice parent;
+
+ ClutterInputDeviceEvdevPrivate *priv;
+};
+
+G_DEFINE_TYPE (ClutterInputDeviceEvdev,
+ clutter_input_device_evdev,
+ CLUTTER_TYPE_INPUT_DEVICE)
+
+static GParamSpec *obj_props[PROP_LAST];
+
+static void
+clutter_input_device_evdev_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterInputDeviceEvdev *input = CLUTTER_INPUT_DEVICE_EVDEV (object);
+ ClutterInputDeviceEvdevPrivate *priv = input->priv;
+
+ switch (property_id)
+ {
+ case PROP_SYSFS_PATH:
+ g_value_set_string (value, priv->sysfs_path);
+ break;
+ case PROP_DEVICE_PATH:
+ g_value_set_string (value, priv->device_path);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_input_device_evdev_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterInputDeviceEvdev *input = CLUTTER_INPUT_DEVICE_EVDEV (object);
+ ClutterInputDeviceEvdevPrivate *priv = input->priv;
+
+ switch (property_id)
+ {
+ case PROP_SYSFS_PATH:
+ priv->sysfs_path = g_value_dup_string (value);
+ break;
+ case PROP_DEVICE_PATH:
+ priv->device_path = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_input_device_evdev_finalize (GObject *object)
+{
+ ClutterInputDeviceEvdev *input = CLUTTER_INPUT_DEVICE_EVDEV (object);
+ ClutterInputDeviceEvdevPrivate *priv = input->priv;
+
+ g_free (priv->sysfs_path);
+ g_free (priv->device_path);
+
+ G_OBJECT_CLASS (clutter_input_device_evdev_parent_class)->finalize (object);
+}
+
+static void
+clutter_input_device_evdev_class_init (ClutterInputDeviceEvdevClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterInputDeviceEvdevPrivate));
+
+ object_class->get_property = clutter_input_device_evdev_get_property;
+ object_class->set_property = clutter_input_device_evdev_set_property;
+ object_class->finalize = clutter_input_device_evdev_finalize;
+
+ /*
+ * ClutterInputDeviceEvdev:udev-device:
+ *
+ * The Sysfs path of the device
+ *
+ * Since: 1.6
+ */
+ pspec =
+ g_param_spec_string ("sysfs-path",
+ P_("sysfs Path"),
+ P_("Path of the device in sysfs"),
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE);
+ obj_props[PROP_SYSFS_PATH] = pspec;
+ g_object_class_install_property (object_class, PROP_SYSFS_PATH, pspec);
+
+ /*
+ * ClutterInputDeviceEvdev:device-path
+ *
+ * The path of the device file.
+ *
+ * Since: 1.6
+ */
+ pspec =
+ g_param_spec_string ("device-path",
+ P_("Device Path"),
+ P_("Path of the device node"),
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE);
+ obj_props[PROP_DEVICE_PATH] = pspec;
+ g_object_class_install_property (object_class, PROP_DEVICE_PATH, pspec);
+}
+
+static void
+clutter_input_device_evdev_init (ClutterInputDeviceEvdev *self)
+{
+ self->priv = INPUT_DEVICE_EVDEV_PRIVATE (self);
+}
+
+ClutterInputDeviceEvdev *
+_clutter_input_device_evdev_new (void)
+{
+ return g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV, NULL);
+}
+
+const gchar *
+_clutter_input_device_evdev_get_sysfs_path (ClutterInputDeviceEvdev *device)
+{
+ g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_EVDEV (device), NULL);
+
+ return device->priv->sysfs_path;
+}
+
+const gchar *
+_clutter_input_device_evdev_get_device_path (ClutterInputDeviceEvdev *device)
+{
+ g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_EVDEV (device), NULL);
+
+ return device->priv->device_path;
+}
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __CLUTTER_INPUT_DEVICE_EVDEV_H__
+#define __CLUTTER_INPUT_DEVICE_EVDEV_H__
+
+#include <glib-object.h>
+#include <gudev/gudev.h>
+
+#include <clutter/clutter-input-device.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_INPUT_DEVICE_EVDEV clutter_input_device_evdev_get_type()
+
+#define CLUTTER_INPUT_DEVICE_EVDEV(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdev))
+
+#define CLUTTER_INPUT_DEVICE_EVDEV_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdevClass))
+
+#define CLUTTER_IS_INPUT_DEVICE_EVDEV(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV))
+
+#define CLUTTER_IS_INPUT_DEVICE_EVDEV_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV))
+
+#define CLUTTER_INPUT_DEVICE_EVDEV_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdevClass))
+
+typedef struct _ClutterInputDeviceEvdev ClutterInputDeviceEvdev;
+
+GType clutter_input_device_evdev_get_type (void) G_GNUC_CONST;
+
+ClutterInputDeviceEvdev * _clutter_input_device_evdev_new (void);
+const gchar * _clutter_input_device_evdev_get_sysfs_path (ClutterInputDeviceEvdev *device);
+const gchar * _clutter_input_device_evdev_get_device_path (ClutterInputDeviceEvdev *device);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_INPUT_DEVICE_EVDEV_H__ */
AS_IF([test x"$found_gdl" = "xno"], [AC_MSG_ERROR([libgdl.h not found])])
- FLAVOUR_LIBS="$FLAVOUR_LIBS -lgdl"
+ # evdev
+ PKG_CHECK_MODULES(EVDEV, [gudev-1.0 xkbcommon],
+ [have_evdev=yes], [have_evdev=no])
+ AS_IF([test "x$have_evdev" = "xyes"],
+ [AC_DEFINE([HAVE_EVDEV], 1,
+ [Have evdev support for input handling])]
+ )
+
+ FLAVOUR_CFLAGS="$FLAVOUR_CFLAGS $EVDEV_CFLAGS"
+ FLAVOUR_LIBS="$FLAVOUR_LIBS -lgdl $EVDEV_LIBS"
],
[fruity],
)
AM_CONDITIONAL(USE_TSLIB, [test "x$have_tslib" = "xyes"])
+AM_CONDITIONAL(SUPPORT_EVDEV, [test "x$have_evdev" = "xyes"])
AM_CONDITIONAL(USE_GLES2_WRAPPER, [test "x$use_gles2_wrapper" = "xyes"])