diff --git a/configure.ac b/configure.ac index 8e0f1c93..08472cf0 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,9 @@ AC_PROG_CC LT_PREREQ([2.2]) LT_INIT +AC_CHECK_DECL(EPOLL_CLOEXEC, [], + [AC_MSG_ERROR("EPOLL_CLOEXEC is needed to compile libinput")], + [[#include ]]) AC_CHECK_DECL(TFD_CLOEXEC,[], [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile libinput")], [[#include ]]) diff --git a/src/Makefile.am b/src/Makefile.am index 905bcd1c..c1e31499 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,8 @@ include_HEADERS = \ libinput_la_SOURCES = \ libinput.c \ libinput.h \ + libinput-util.c \ + libinput-util.h \ evdev.c \ evdev.h \ evdev-touchpad.c \ diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c index 6268dffa..a673a7b7 100644 --- a/src/evdev-touchpad.c +++ b/src/evdev-touchpad.c @@ -137,7 +137,7 @@ struct touchpad_dispatch { enum fsm_state state; struct { int fd; - struct libinput_fd_handle *fd_handle; + struct libinput_source *source; } timer; } fsm; @@ -440,17 +440,15 @@ push_fsm_event(struct touchpad_dispatch *touchpad, } 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 @@ -711,12 +709,10 @@ touchpad_destroy(struct evdev_dispatch *dispatch) { 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); } @@ -801,13 +797,13 @@ touchpad_init(struct touchpad_dispatch *touchpad, 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; diff --git a/src/evdev.c b/src/evdev.c index c326a433..4f107ea5 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -426,9 +426,10 @@ evdev_process_events(struct evdev_device *device, } } -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; @@ -446,18 +447,17 @@ evdev_device_dispatch(struct evdev_device *device) 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 @@ -608,6 +608,7 @@ evdev_configure_device(struct evdev_device *device) LIBINPUT_EXPORT struct libinput_device * libinput_device_create_evdev( + struct libinput *libinput, const char *devnode, int fd, const struct libinput_device_interface *device_interface, @@ -620,6 +621,7 @@ libinput_device_create_evdev( if (device == NULL) return NULL; + device->base.libinput = libinput; device->base.device_interface = device_interface; device->base.device_interface_data = user_data; @@ -652,6 +654,11 @@ libinput_device_create_evdev( 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: diff --git a/src/evdev.h b/src/evdev.h index 6bb62ff9..1b45aed0 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -67,6 +67,8 @@ enum evdev_device_seat_capability { struct evdev_device { struct libinput_device base; + struct libinput_source *source; + struct evdev_dispatch *dispatch; char *devnode; char *devname; @@ -130,8 +132,8 @@ struct evdev_dispatch { 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); diff --git a/src/libinput-private.h b/src/libinput-private.h index d245635a..6796ccfa 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -24,10 +24,11 @@ #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; @@ -36,6 +37,30 @@ struct libinput_device { 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, @@ -74,26 +99,4 @@ touch_notify_touch(struct libinput_device *device, 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 */ diff --git a/src/libinput-util.c b/src/libinput-util.c new file mode 100644 index 00000000..9d9d4dd8 --- /dev/null +++ b/src/libinput-util.c @@ -0,0 +1,62 @@ +/* + * 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; +} diff --git a/src/libinput-util.h b/src/libinput-util.h new file mode 100644 index 00000000..1395106e --- /dev/null +++ b/src/libinput-util.h @@ -0,0 +1,91 @@ +/* + * 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 */ diff --git a/src/libinput.c b/src/libinput.c index fd0fb1e7..af00725d 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -25,15 +25,140 @@ #include #include #include +#include +#include #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, @@ -53,7 +178,9 @@ 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 @@ -74,7 +201,9 @@ pointer_notify_motion(struct libinput_device *device, .dy = dy, }; - post_event(device, LIBINPUT_EVENT_POINTER_MOTION, &motion_event->base); + post_device_event(device, + LIBINPUT_EVENT_POINTER_MOTION, + &motion_event->base); } void @@ -95,9 +224,9 @@ pointer_notify_motion_absolute(struct libinput_device *device, .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 @@ -118,7 +247,9 @@ pointer_notify_button(struct libinput_device *device, .state = state, }; - post_event(device, LIBINPUT_EVENT_POINTER_BUTTON, &button_event->base); + post_device_event(device, + LIBINPUT_EVENT_POINTER_BUTTON, + &button_event->base); } void @@ -139,7 +270,9 @@ pointer_notify_axis(struct libinput_device *device, .value = value, }; - post_event(device, LIBINPUT_EVENT_POINTER_AXIS, &axis_event->base); + post_device_event(device, + LIBINPUT_EVENT_POINTER_AXIS, + &axis_event->base); } void @@ -164,23 +297,18 @@ touch_notify_touch(struct libinput_device *device, .touch_type = touch_type, }; - post_event(device, LIBINPUT_EVENT_TOUCH_TOUCH, &touch_event->base); + post_device_event(device, + LIBINPUT_EVENT_TOUCH_TOUCH, + &touch_event->base); } -static void -init_event_base(struct libinput_event *event, enum libinput_event_type type) +void +libinput_post_event(struct libinput *libinput, + struct libinput_event *event) { - event->type = type; -} - -static void -post_event(struct libinput_device *device, - enum libinput_event_type type, - 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; @@ -197,62 +325,55 @@ post_event(struct libinput_device *device, 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) diff --git a/src/libinput.h b/src/libinput.h index 745660c2..67b7c1e2 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -77,6 +77,7 @@ enum libinput_event_type { struct libinput_event { enum libinput_event_type type; + struct libinput_device *device; }; struct libinput_event_keyboard_key { @@ -138,36 +139,39 @@ struct libinput_device_interface { 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 * +libinput_create(void); + +int +libinput_get_fd(struct libinput *libinput); + +int +libinput_dispatch(struct libinput *libinput); + +struct libinput_event * +libinput_get_event(struct libinput *libinput); + +void +libinput_destroy(struct libinput *libinput); + struct libinput_device * -libinput_device_create_evdev(const char *devnode, +libinput_device_create_evdev(struct libinput *libinput, + const char *devnode, int fd, const struct libinput_device_interface *interface, void *user_data); -int -libinput_device_dispatch(struct libinput_device *device); - -struct libinput_event * -libinput_device_get_event(struct libinput_device *device); - 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);