Add libinput_create_from_path
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 10 Dec 2013 03:20:36 +0000 (13:20 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Fri, 10 Jan 2014 01:08:24 +0000 (11:08 +1000)
Hooking libinput up to udev isn't always possible, especially if libinput were
to be used in the X server which already has the udev handling built-in.
Add an option to create a context from a path.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/Makefile.am
src/libinput.h
src/path.c [new file with mode: 0644]
src/path.h [new file with mode: 0644]

index d3dc35750ecc046fe4dc14ee072bf950a3ed15f0..6e27b3b49f9cbf40a026a674929655bb56517367 100644 (file)
@@ -13,6 +13,8 @@ libinput_la_SOURCES =                 \
        evdev-touchpad.c                \
        filter.c                        \
        filter.h                        \
+       path.h                          \
+       path.c                          \
        udev-seat.c                     \
        udev-seat.h
 
index 0d03073dbabba541ab77a19eca3157817b204c84..d1c6746a54090434c82500a89e21d2c0ce038ce0 100644 (file)
@@ -447,6 +447,25 @@ libinput_create_from_udev(const struct libinput_interface *interface,
                          void *user_data,
                          struct udev *udev,
                          const char *seat_id);
+/**
+ * @ingroup base
+ *
+ * Create a new libinput context from the given path. This context
+ * represents one single device only, it will not respond to new devices
+ * being added and reading from the device after it was removed will fail.
+ *
+ * @param interface The callback interface
+ * @param user_data Caller-specific data passed to the various callback
+ * interfaces.
+ * @param path Path to an input device
+ *
+ * @return An initialized libinput context, ready to handle events or NULL on
+ * error.
+ */
+struct libinput *
+libinput_create_from_path(const struct libinput_interface *interface,
+                         void *user_data,
+                         const char *path);
 
 /**
  * @ingroup base
diff --git a/src/path.c b/src/path.c
new file mode 100644 (file)
index 0000000..cafe1fe
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <libudev.h>
+
+#include "path.h"
+#include "evdev.h"
+
+int path_input_process_event(struct libinput_event);
+static void path_seat_destroy(struct libinput_seat *seat);
+
+static void
+path_input_disable(struct libinput *libinput)
+{
+       struct path_input *input = (struct path_input*)libinput;
+       struct evdev_device *device = input->device;
+       struct path_seat *seat, *tmp;
+
+       if (device) {
+               close_restricted(libinput, device->fd);
+               evdev_device_remove(device);
+               input->device = NULL;
+       }
+
+       /* should only be one seat anyway */
+       list_for_each_safe(seat, tmp, &libinput->seat_list, base.link) {
+               notify_removed_seat(&seat->base);
+               list_remove(&seat->base.link);
+               list_init(&seat->base.link);
+               libinput_seat_unref(&seat->base);
+       }
+}
+
+static void
+path_seat_destroy(struct libinput_seat *seat)
+{
+       struct path_seat *pseat = (struct path_seat*)seat;
+       free(pseat);
+}
+
+static struct path_seat*
+path_seat_create(struct path_input *input)
+{
+       struct path_seat *seat;
+
+       seat = zalloc(sizeof(*seat));
+       if (!seat)
+               return NULL;
+
+       seat->name = "default";
+
+       libinput_seat_init(&seat->base, &input->base, seat->name, path_seat_destroy);
+       list_insert(&input->base.seat_list, &seat->base.link);
+       notify_added_seat(&seat->base);
+
+       return seat;
+}
+
+static char *
+path_get_sysname(const char *path)
+{
+       struct udev *udev = NULL;
+       struct udev_device *device = NULL;
+       struct stat st;
+       char *syspath = NULL;
+
+       udev = udev_new();
+       if (!udev)
+               goto out;
+
+       if (stat(path, &st) < 0)
+               goto out;
+
+       device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
+       if (!device)
+               goto out;
+
+       syspath = strdup(udev_device_get_syspath(device));
+out:
+       if (device)
+               udev_device_unref(device);
+       if (udev)
+               udev_unref(udev);
+       return syspath;
+}
+
+static int
+path_input_enable(struct libinput *libinput)
+{
+       struct path_input *input = (struct path_input*)libinput;
+       struct path_seat *seat;
+       struct evdev_device *device;
+       const char *devnode = input->path;
+       char *syspath;
+       int fd;
+
+       if (input->device)
+               return 0;
+
+       fd = open_restricted(libinput, input->path, O_RDWR|O_NONBLOCK);
+       if (fd < 0) {
+               log_info("opening input device '%s' failed.\n", devnode);
+               return -1;
+       }
+
+       syspath = path_get_sysname(devnode);
+       if (!syspath) {
+               close_restricted(libinput, fd);
+               log_info("failed to obtain syspath for device '%s'.\n", devnode);
+               return -1;
+       }
+
+       seat = path_seat_create(input);
+
+       device = evdev_device_create(&seat->base, devnode, syspath, fd);
+       free(syspath);
+
+       if (device == EVDEV_UNHANDLED_DEVICE) {
+               close_restricted(libinput, fd);
+               log_info("not using input device '%s'.\n", devnode);
+               libinput_seat_unref(&seat->base);
+               return -1;
+       } else if (device == NULL) {
+               close_restricted(libinput, fd);
+               log_info("failed to create input device '%s'.\n", devnode);
+               libinput_seat_unref(&seat->base);
+               return -1;
+       }
+
+       input->device = device;
+
+       return 0;
+}
+
+static void
+path_input_destroy(struct libinput *input)
+{
+       struct path_input *path_input = (struct path_input*)input;
+       free(path_input->path);
+}
+
+static const struct libinput_interface_backend interface_backend = {
+       .resume = path_input_enable,
+       .suspend = path_input_disable,
+       .destroy = path_input_destroy,
+};
+
+LIBINPUT_EXPORT struct libinput *
+libinput_create_from_path(const struct libinput_interface *interface,
+                         void *user_data,
+                         const char *path)
+{
+       struct path_input *input;
+
+       if (!interface || !path)
+               return NULL;
+
+       input = zalloc(sizeof *input);
+       if (!input)
+               return NULL;
+
+       if (libinput_init(&input->base, interface,
+                         &interface_backend, user_data) != 0) {
+               free(input);
+               return NULL;
+       }
+
+       input->path = strdup(path);
+
+       if (path_input_enable(&input->base) < 0) {
+               libinput_destroy(&input->base);
+               return NULL;
+       }
+
+       return &input->base;
+}
diff --git a/src/path.h b/src/path.h
new file mode 100644 (file)
index 0000000..72cc547
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PATH_H_
+#define _PATH_H_
+
+#include "config.h"
+#include "libinput-private.h"
+
+struct path_input {
+       struct libinput base;
+       char *path;
+       struct evdev_device *device;
+};
+
+struct path_seat {
+       struct libinput_seat base;
+       const char *name;
+};
+
+int path_input_process_event(struct libinput_event);
+
+#endif