LT_PREREQ([2.2])
LT_INIT
+AC_CHECK_DECL(EPOLL_CLOEXEC, [],
+ [AC_MSG_ERROR("EPOLL_CLOEXEC is needed to compile libinput")],
+ [[#include <sys/epoll.h>]])
AC_CHECK_DECL(TFD_CLOEXEC,[],
[AC_MSG_ERROR("TFD_CLOEXEC is needed to compile libinput")],
[[#include <sys/timerfd.h>]])
libinput_la_SOURCES = \
libinput.c \
libinput.h \
+ libinput-util.c \
+ libinput-util.h \
evdev.c \
evdev.h \
evdev-touchpad.c \
enum fsm_state state;
struct {
int fd;
- struct libinput_fd_handle *fd_handle;
+ struct libinput_source *source;
} timer;
} fsm;
}
static void
-fsm_timeout_handler(int fd, void *data)
+fsm_timeout_handler(void *data)
{
- struct evdev_device *device = data;
- struct touchpad_dispatch *touchpad =
- (struct touchpad_dispatch *) device->dispatch;
+ struct touchpad_dispatch *touchpad = data;
uint64_t expires;
int len;
struct timespec ts;
uint32_t now;
- len = read(fd, &expires, sizeof expires);
+ len = read(touchpad->fsm.timer.fd, &expires, sizeof expires);
if (len != sizeof expires)
/* This will only happen if the application made the fd
* non-blocking, but this function should only be called
{
struct touchpad_dispatch *touchpad =
(struct touchpad_dispatch *) dispatch;
+ struct libinput *libinput = touchpad->device->base.libinput;
touchpad->filter->interface->destroy(touchpad->filter);
- touchpad->device->base.device_interface->remove_fd(
- touchpad->fsm.timer.fd_handle,
- touchpad->device->base.device_interface_data);
- close(touchpad->fsm.timer.fd);
+ libinput_remove_source(libinput, touchpad->fsm.timer.source);
free(touchpad->fsm.events);
free(dispatch);
}
touchpad->fsm.state = FSM_IDLE;
touchpad->fsm.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
- touchpad->fsm.timer.fd_handle =
- touchpad->device->base.device_interface->add_fd(
- touchpad->fsm.timer.fd,
- fsm_timeout_handler,
- touchpad->device->base.device_interface_data);
+ touchpad->fsm.timer.source =
+ libinput_add_fd(touchpad->device->base.libinput,
+ touchpad->fsm.timer.fd,
+ fsm_timeout_handler,
+ touchpad);
- if (touchpad->fsm.timer.fd_handle == NULL) {
+ if (touchpad->fsm.timer.source == NULL) {
close(touchpad->fsm.timer.fd);
accel->interface->destroy(accel);
return -1;
}
}
-int
-evdev_device_dispatch(struct evdev_device *device)
+static void
+evdev_device_dispatch(void *data)
{
+ struct evdev_device *device = data;
int fd = device->fd;
struct input_event ev[32];
int len;
if (len < 0 || len % sizeof ev[0] != 0) {
if (len < 0 && errno != EAGAIN && errno != EINTR) {
- device->base.device_interface->device_lost(
- device->base.device_interface_data);
+ libinput_remove_source(device->base.libinput,
+ device->source);
+ device->source = NULL;
}
- return 1;
+ return;
}
evdev_process_events(device, ev, len / sizeof ev[0]);
} while (len > 0);
-
- return 1;
}
static int
LIBINPUT_EXPORT struct libinput_device *
libinput_device_create_evdev(
+ struct libinput *libinput,
const char *devnode,
int fd,
const struct libinput_device_interface *device_interface,
if (device == NULL)
return NULL;
+ device->base.libinput = libinput;
device->base.device_interface = device_interface;
device->base.device_interface_data = user_data;
if (device->dispatch == NULL)
goto err;
+ device->source =
+ libinput_add_fd(libinput, fd, evdev_device_dispatch, device);
+ if (!device->source)
+ goto err;
+
return &device->base;
err:
struct evdev_device {
struct libinput_device base;
+ struct libinput_source *source;
+
struct evdev_dispatch *dispatch;
char *devnode;
char *devname;
struct evdev_dispatch *
evdev_touchpad_create(struct evdev_device *device);
-int
-evdev_device_dispatch(struct evdev_device *device);
+void
+evdev_device_proces_event(struct libinput_event *event);
void
evdev_device_led_update(struct evdev_device *device, enum libinput_led leds);
#define LIBINPUT_PRIVATE_H
#include "libinput.h"
+#include "libinput-util.h"
-struct libinput_device {
- const struct libinput_device_interface *device_interface;
- void *device_interface_data;
+struct libinput {
+ int epoll_fd;
+ struct list source_destroy_list;
struct libinput_event **events;
size_t events_count;
size_t events_out;
};
+struct libinput_device {
+ struct libinput *libinput;
+ const struct libinput_device_interface *device_interface;
+ void *device_interface_data;
+};
+
+typedef void (*libinput_source_dispatch_t)(void *data);
+
+struct libinput_source;
+
+struct libinput_source *
+libinput_add_fd(struct libinput *libinput,
+ int fd,
+ libinput_source_dispatch_t dispatch,
+ void *data);
+
+void
+libinput_remove_source(struct libinput *libinput,
+ struct libinput_source *source);
+
+void
+libinput_post_event(struct libinput *libinput,
+ struct libinput_event *event);
+
void
keyboard_notify_key(struct libinput_device *device,
uint32_t time,
li_fixed_t y,
enum libinput_touch_type touch_type);
-static inline li_fixed_t li_fixed_from_int(int i)
-{
- return i * 256;
-}
-
-static inline li_fixed_t
-li_fixed_from_double(double d)
-{
- union {
- double d;
- int64_t i;
- } u;
-
- u.d = d + (3LL << (51 - 8));
-
- return u.i;
-}
-
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-
-#define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
-
#endif /* LIBINPUT_PRIVATE_H */
--- /dev/null
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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.
+ */
+
+/*
+ * This list data structure is verbatim copy from wayland-util.h from the
+ * Wayland project; except that wl_ prefix has been removed.
+ */
+
+#include "config.h"
+
+#include "libinput-private.h"
+
+void
+list_init(struct list *list)
+{
+ list->prev = list;
+ list->next = list;
+}
+
+void
+list_insert(struct list *list, struct list *elm)
+{
+ elm->prev = list;
+ elm->next = list->next;
+ list->next = elm;
+ elm->next->prev = elm;
+}
+
+void
+list_remove(struct list *elm)
+{
+ elm->prev->next = elm->next;
+ elm->next->prev = elm->prev;
+ elm->next = NULL;
+ elm->prev = NULL;
+}
+
+int
+list_empty(const struct list *list)
+{
+ return list->next == list;
+}
--- /dev/null
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * 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 LIBINPUT_UTIL_H
+#define LIBINPUT_UTIL_H
+
+/*
+ * This list data structure is a verbatim copy from wayland-util.h from the
+ * Wayland project; except that wl_ prefix has been removed.
+ */
+
+struct list {
+ struct list *prev;
+ struct list *next;
+};
+
+void list_init(struct list *list);
+void list_insert(struct list *list, struct list *elm);
+void list_remove(struct list *elm);
+int list_empty(const struct list *list);
+
+#ifdef __GNUC__
+#define container_of(ptr, sample, member) \
+ (__typeof__(sample))((char *)(ptr) - \
+ ((char *)&(sample)->member - (char *)(sample)))
+#else
+#define container_of(ptr, sample, member) \
+ (void *)((char *)(ptr) - \
+ ((char *)&(sample)->member - (char *)(sample)))
+#endif
+
+#define list_for_each(pos, head, member) \
+ for (pos = 0, pos = container_of((head)->next, pos, member); \
+ &pos->member != (head); \
+ pos = container_of(pos->member.next, pos, member))
+
+#define list_for_each_safe(pos, tmp, head, member) \
+ for (pos = 0, tmp = 0, \
+ pos = container_of((head)->next, pos, member), \
+ tmp = container_of((pos)->member.next, tmp, member); \
+ &pos->member != (head); \
+ pos = tmp, \
+ tmp = container_of(pos->member.next, tmp, member))
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*
+ * This fixed point implementation is a verbatim copy from wayland-util.h from
+ * the Wayland project, with the wl_ prefix renamed li_.
+ */
+
+static inline li_fixed_t li_fixed_from_int(int i)
+{
+ return i * 256;
+}
+
+static inline li_fixed_t
+li_fixed_from_double(double d)
+{
+ union {
+ double d;
+ int64_t i;
+ } u;
+
+ u.d = d + (3LL << (51 - 8));
+
+ return u.i;
+}
+
+#define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
+
+#endif /* LIBINPUT_UTIL_H */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/epoll.h>
+#include <unistd.h>
#include "libinput.h"
#include "evdev.h"
#include "libinput-private.h"
+struct libinput_source {
+ libinput_source_dispatch_t dispatch;
+ void *user_data;
+ int fd;
+ struct list link;
+};
+
+struct libinput_source *
+libinput_add_fd(struct libinput *libinput,
+ int fd,
+ libinput_source_dispatch_t dispatch,
+ void *user_data)
+{
+ struct libinput_source *source;
+ struct epoll_event ep;
+
+ source = malloc(sizeof *source);
+ if (!source)
+ return NULL;
+
+ source->dispatch = dispatch;
+ source->user_data = user_data;
+ source->fd = fd;
+
+ memset(&ep, 0, sizeof ep);
+ ep.events = EPOLLIN;
+ ep.data.ptr = source;
+
+ if (epoll_ctl(libinput->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
+ close(source->fd);
+ free(source);
+ return NULL;
+ }
+
+ return source;
+}
+
+void
+libinput_remove_source(struct libinput *libinput,
+ struct libinput_source *source)
+{
+ epoll_ctl(libinput->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
+ close(source->fd);
+ source->fd = -1;
+ list_insert(&libinput->source_destroy_list, &source->link);
+}
+
+LIBINPUT_EXPORT struct libinput *
+libinput_create(void)
+{
+ struct libinput *libinput;
+
+ libinput = zalloc(sizeof *libinput);
+ if (!libinput)
+ return NULL;
+
+ list_init(&libinput->source_destroy_list);
+
+ libinput->epoll_fd = epoll_create1(EPOLL_CLOEXEC);;
+ if (libinput->epoll_fd < 0)
+ return NULL;
+
+ return libinput;
+}
+
+LIBINPUT_EXPORT void
+libinput_destroy(struct libinput *libinput)
+{
+ struct libinput_event *event;
+
+ while ((event = libinput_get_event(libinput)))
+ free(event);
+ free(libinput->events);
+
+ close(libinput->epoll_fd);
+ free(libinput);
+}
+
+LIBINPUT_EXPORT int
+libinput_get_fd(struct libinput *libinput)
+{
+ return libinput->epoll_fd;
+}
+
+LIBINPUT_EXPORT int
+libinput_dispatch(struct libinput *libinput)
+{
+ struct libinput_source *source, *next;
+ struct epoll_event ep[32];
+ int i, count;
+
+ count = epoll_wait(libinput->epoll_fd, ep, ARRAY_LENGTH(ep), 0);
+ if (count < 0)
+ return -1;
+
+ for (i = 0; i < count; ++i) {
+ source = ep[i].data.ptr;
+ if (source->fd == -1)
+ continue;
+
+ source->dispatch(source->user_data);
+ }
+
+ list_for_each_safe(source, next, &libinput->source_destroy_list, link)
+ free(source);
+ list_init(&libinput->source_destroy_list);
+
+ return 0;
+}
+
static void
-post_event(struct libinput_device *device,
- enum libinput_event_type type,
- struct libinput_event *event);
+init_event_base(struct libinput_event *event,
+ enum libinput_event_type type,
+ struct libinput_device *device)
+{
+ event->type = type;
+ event->device = device;
+}
+
+static void
+post_device_event(struct libinput_device *device,
+ enum libinput_event_type type,
+ struct libinput_event *event)
+{
+ init_event_base(event, type, device);
+ libinput_post_event(device->libinput, event);
+}
void
keyboard_notify_key(struct libinput_device *device,
.state = state,
};
- post_event(device, LIBINPUT_EVENT_KEYBOARD_KEY, &key_event->base);
+ post_device_event(device,
+ LIBINPUT_EVENT_KEYBOARD_KEY,
+ &key_event->base);
}
void
.dy = dy,
};
- post_event(device, LIBINPUT_EVENT_POINTER_MOTION, &motion_event->base);
+ post_device_event(device,
+ LIBINPUT_EVENT_POINTER_MOTION,
+ &motion_event->base);
}
void
.y = y,
};
- post_event(device,
- LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
- &motion_absolute_event->base);
+ post_device_event(device,
+ LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
+ &motion_absolute_event->base);
}
void
.state = state,
};
- post_event(device, LIBINPUT_EVENT_POINTER_BUTTON, &button_event->base);
+ post_device_event(device,
+ LIBINPUT_EVENT_POINTER_BUTTON,
+ &button_event->base);
}
void
.value = value,
};
- post_event(device, LIBINPUT_EVENT_POINTER_AXIS, &axis_event->base);
+ post_device_event(device,
+ LIBINPUT_EVENT_POINTER_AXIS,
+ &axis_event->base);
}
void
.touch_type = touch_type,
};
- post_event(device, LIBINPUT_EVENT_TOUCH_TOUCH, &touch_event->base);
-}
-
-static void
-init_event_base(struct libinput_event *event, enum libinput_event_type type)
-{
- event->type = type;
+ post_device_event(device,
+ LIBINPUT_EVENT_TOUCH_TOUCH,
+ &touch_event->base);
}
-static void
-post_event(struct libinput_device *device,
- enum libinput_event_type type,
- struct libinput_event *event)
+void
+libinput_post_event(struct libinput *libinput,
+ struct libinput_event *event)
{
- struct libinput_event **events = device->events;
- size_t events_len = device->events_len;
- size_t events_count = device->events_count;
+ struct libinput_event **events = libinput->events;
+ size_t events_len = libinput->events_len;
+ size_t events_count = libinput->events_count;
size_t move_len;
size_t new_out;
return;
}
- if (device->events_count > 0 && device->events_in == 0) {
- device->events_in = device->events_len;
- } else if (device->events_count > 0 &&
- device->events_out >= device->events_in) {
- move_len = device->events_len - device->events_out;
+ if (libinput->events_count > 0 && libinput->events_in == 0) {
+ libinput->events_in = libinput->events_len;
+ } else if (libinput->events_count > 0 &&
+ libinput->events_out >= libinput->events_in) {
+ move_len = libinput->events_len - libinput->events_out;
new_out = events_len - move_len;
memmove(events + new_out,
- device->events + device->events_out,
+ libinput->events + libinput->events_out,
move_len * sizeof *events);
- device->events_out = new_out;
+ libinput->events_out = new_out;
}
- device->events = events;
- device->events_len = events_len;
+ libinput->events = events;
+ libinput->events_len = events_len;
}
- init_event_base(event, type);
-
- device->events_count = events_count;
- events[device->events_in] = event;
- device->events_in = (device->events_in + 1) % device->events_len;
+ libinput->events_count = events_count;
+ events[libinput->events_in] = event;
+ libinput->events_in = (libinput->events_in + 1) % libinput->events_len;
}
LIBINPUT_EXPORT struct libinput_event *
-libinput_device_get_event(struct libinput_device *device)
+libinput_get_event(struct libinput *libinput)
{
struct libinput_event *event;
- if (device->events_count == 0)
+ if (libinput->events_count == 0)
return NULL;
- event = device->events[device->events_out];
- device->events_out = (device->events_out + 1) % device->events_len;
- device->events_count--;
+ event = libinput->events[libinput->events_out];
+ libinput->events_out =
+ (libinput->events_out + 1) % libinput->events_len;
+ libinput->events_count--;
return event;
}
-LIBINPUT_EXPORT int
-libinput_device_dispatch(struct libinput_device *device)
-{
- return evdev_device_dispatch((struct evdev_device *) device);
-}
-
LIBINPUT_EXPORT void
libinput_device_destroy(struct libinput_device *device)
{
- struct libinput_event *event;
-
- while ((event = libinput_device_get_event(device)))
- free(event);
- free(device->events);
-
evdev_device_destroy((struct evdev_device *) device);
}
+LIBINPUT_EXPORT void *
+libinput_device_get_user_data(struct libinput_device *device)
+{
+ return device->device_interface_data;
+}
+
LIBINPUT_EXPORT void
libinput_device_led_update(struct libinput_device *device,
enum libinput_led leds)
struct libinput_event {
enum libinput_event_type type;
+ struct libinput_device *device;
};
struct libinput_event_keyboard_key {
void (*get_current_screen_dimensions)(int *width,
int *height,
void *data);
-
- /* */
- struct libinput_fd_handle * (*add_fd)(int fd,
- libinput_fd_callback callback,
- void *data);
- void (*remove_fd)(struct libinput_fd_handle *fd_container,
- void *data);
-
- /* */
- void (*device_lost)(void *data);
};
-struct libinput_seat;
+struct libinput;
struct libinput_device;
-struct libinput_device *
-libinput_device_create_evdev(const char *devnode,
- int fd,
- const struct libinput_device_interface *interface,
- void *user_data);
+struct libinput *
+libinput_create(void);
int
-libinput_device_dispatch(struct libinput_device *device);
+libinput_get_fd(struct libinput *libinput);
+
+int
+libinput_dispatch(struct libinput *libinput);
struct libinput_event *
-libinput_device_get_event(struct libinput_device *device);
+libinput_get_event(struct libinput *libinput);
+
+void
+libinput_destroy(struct libinput *libinput);
+
+struct libinput_device *
+libinput_device_create_evdev(struct libinput *libinput,
+ const char *devnode,
+ int fd,
+ const struct libinput_device_interface *interface,
+ void *user_data);
void
libinput_device_destroy(struct libinput_device *device);
+void *
+libinput_device_get_user_data(struct libinput_device *device);
+
void
libinput_device_led_update(struct libinput_device *device,
enum libinput_led leds);