Port udev-seat to be used in libinput

This patch ports udev-seat from weston to libinput, including adapting
libinput internals and API to provide seat and device discovery.

The public API is extended with device discovery, object reference, a
seat object. As libinput takes care of creating and destroying its
objects user data getter/setter is added in order to make it possible
for the client to directly associate an object application side with an
object library side.

Device discovery API is made up of the 'seat added', 'seat removed',
'device added' and 'device removed' events. The seat added/removed
events contains a pointer to a libinput_seat struct, while the device
added/removed events contains a pointer to a libinput_device event.

The objects are reference counted with libinput holding one reference by
default. The application can increase the reference count with
libinput_seat_ref() and libinput_device_ref() and decrease the reference
count with libinput_seat_unref() and libinput_device_unref().

The basic event struct is changed to have a 'target' union parameter
that can be either a libinput, libinput_seat or libinput_device struct
pointer.

There is one known problem with the current API that is the potentially
racy initialization.

The problem is when a device is both discovered and lost during initial
dispatchig, causing libinput to first queue a 'added' message, creating
the device with default reference count 1, then before going back to the
application queuing a 'removed' message, while at same time decreasing
reference count of the device to 0, causing it o be destroyed. The queue
will at this state contain two messages with pointers to free:ed memory.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
Jonas Ådahl 2013-11-23 13:04:32 +01:00
parent c0af815eae
commit 56f7ddec82
9 changed files with 531 additions and 222 deletions

View file

@ -12,7 +12,9 @@ libinput_la_SOURCES = \
evdev.h \ evdev.h \
evdev-touchpad.c \ evdev-touchpad.c \
filter.c \ filter.c \
filter.h filter.h \
udev-seat.c \
udev-seat.h
libinput_la_LIBADD = $(MTDEV_LIBS) libinput_la_LIBADD = $(MTDEV_LIBS)
libinput_la_CFLAGS = $(MTDEV_CFLAGS) \ libinput_la_CFLAGS = $(MTDEV_CFLAGS) \

View file

@ -709,7 +709,7 @@ touchpad_destroy(struct evdev_dispatch *dispatch)
{ {
struct touchpad_dispatch *touchpad = struct touchpad_dispatch *touchpad =
(struct touchpad_dispatch *) dispatch; (struct touchpad_dispatch *) dispatch;
struct libinput *libinput = touchpad->device->base.libinput; struct libinput *libinput = touchpad->device->base.seat->libinput;
touchpad->filter->interface->destroy(touchpad->filter); touchpad->filter->interface->destroy(touchpad->filter);
libinput_remove_source(libinput, touchpad->fsm.timer.source); libinput_remove_source(libinput, touchpad->fsm.timer.source);
@ -798,7 +798,7 @@ touchpad_init(struct touchpad_dispatch *touchpad,
touchpad->fsm.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); touchpad->fsm.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
touchpad->fsm.timer.source = touchpad->fsm.timer.source =
libinput_add_fd(touchpad->device->base.libinput, libinput_add_fd(touchpad->device->base.seat->libinput,
touchpad->fsm.timer.fd, touchpad->fsm.timer.fd,
fsm_timeout_handler, fsm_timeout_handler,
touchpad); touchpad);

View file

@ -227,7 +227,7 @@ evdev_process_touch(struct evdev_device *device,
struct input_event *e, struct input_event *e,
uint32_t time) uint32_t time)
{ {
struct libinput *libinput = device->base.libinput; struct libinput *libinput = device->base.seat->libinput;
int screen_width; int screen_width;
int screen_height; int screen_height;
@ -272,7 +272,7 @@ static inline void
evdev_process_absolute_motion(struct evdev_device *device, evdev_process_absolute_motion(struct evdev_device *device,
struct input_event *e) struct input_event *e)
{ {
struct libinput *libinput = device->base.libinput; struct libinput *libinput = device->base.seat->libinput;
int screen_width; int screen_width;
int screen_height; int screen_height;
@ -434,6 +434,7 @@ static void
evdev_device_dispatch(void *data) evdev_device_dispatch(void *data)
{ {
struct evdev_device *device = data; struct evdev_device *device = data;
struct libinput *libinput = device->base.seat->libinput;
int fd = device->fd; int fd = device->fd;
struct input_event ev[32]; struct input_event ev[32];
int len; int len;
@ -451,7 +452,7 @@ evdev_device_dispatch(void *data)
if (len < 0 || len % sizeof ev[0] != 0) { if (len < 0 || len % sizeof ev[0] != 0) {
if (len < 0 && errno != EAGAIN && errno != EINTR) { if (len < 0 && errno != EAGAIN && errno != EINTR) {
libinput_remove_source(device->base.libinput, libinput_remove_source(libinput,
device->source); device->source);
device->source = NULL; device->source = NULL;
} }
@ -584,36 +585,41 @@ evdev_handle_device(struct evdev_device *device)
return 1; return 1;
} }
static int static void
evdev_configure_device(struct evdev_device *device) evdev_configure_device(struct evdev_device *device)
{ {
if ((device->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) && if ((device->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
(device->caps & EVDEV_BUTTON)) { (device->caps & EVDEV_BUTTON))
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_POINTER);
device->seat_caps |= EVDEV_DEVICE_POINTER; device->seat_caps |= EVDEV_DEVICE_POINTER;
} if ((device->caps & EVDEV_KEYBOARD))
if ((device->caps & EVDEV_KEYBOARD)) {
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_KEYBOARD);
device->seat_caps |= EVDEV_DEVICE_KEYBOARD; device->seat_caps |= EVDEV_DEVICE_KEYBOARD;
} if ((device->caps & EVDEV_TOUCH))
if ((device->caps & EVDEV_TOUCH)) {
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_TOUCH);
device->seat_caps |= EVDEV_DEVICE_TOUCH; device->seat_caps |= EVDEV_DEVICE_TOUCH;
}
return 0;
} }
LIBINPUT_EXPORT struct libinput_device * static void
libinput_device_create_evdev( register_device_capabilities(struct evdev_device *device)
struct libinput *libinput,
const char *devnode,
int fd,
void *user_data)
{ {
if (device->seat_caps & EVDEV_DEVICE_POINTER) {
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_POINTER);
}
if (device->seat_caps & EVDEV_DEVICE_KEYBOARD) {
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_KEYBOARD);
}
if (device->seat_caps & EVDEV_DEVICE_TOUCH) {
device_register_capability(&device->base,
LIBINPUT_DEVICE_CAP_TOUCH);
}
}
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
int fd)
{
struct libinput *libinput = seat->libinput;
struct evdev_device *device; struct evdev_device *device;
char devname[256] = "unknown"; char devname[256] = "unknown";
@ -621,8 +627,7 @@ libinput_device_create_evdev(
if (device == NULL) if (device == NULL)
return NULL; return NULL;
device->base.libinput = libinput; libinput_device_init(&device->base, seat);
device->base.user_data = user_data;
device->seat_caps = 0; device->seat_caps = 0;
device->is_mt = 0; device->is_mt = 0;
@ -644,8 +649,7 @@ libinput_device_create_evdev(
return NULL; return NULL;
} }
if (evdev_configure_device(device) == -1) evdev_configure_device(device);
goto err;
/* If the dispatch was not set up use the fallback. */ /* If the dispatch was not set up use the fallback. */
if (device->dispatch == NULL) if (device->dispatch == NULL)
@ -658,7 +662,11 @@ libinput_device_create_evdev(
if (!device->source) if (!device->source)
goto err; goto err;
return &device->base; list_insert(seat->devices_list.prev, &device->base.link);
notify_added_device(&device->base);
register_device_capabilities(device);
return device;
err: err:
evdev_device_destroy(device); evdev_device_destroy(device);
@ -672,6 +680,12 @@ evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size)
return ioctl(device->fd, EVIOCGKEY(size), keys); return ioctl(device->fd, EVIOCGKEY(size), keys);
} }
const char *
evdev_device_get_output(struct evdev_device *device)
{
return device->output_name;
}
void void
evdev_device_calibrate(struct evdev_device *device, float calibration[6]) evdev_device_calibrate(struct evdev_device *device, float calibration[6])
{ {
@ -680,7 +694,7 @@ evdev_device_calibrate(struct evdev_device *device, float calibration[6])
} }
void void
evdev_device_terminate(struct evdev_device *device) evdev_device_remove(struct evdev_device *device)
{ {
if (device->seat_caps & EVDEV_DEVICE_POINTER) { if (device->seat_caps & EVDEV_DEVICE_POINTER) {
device_unregister_capability(&device->base, device_unregister_capability(&device->base,
@ -694,6 +708,18 @@ evdev_device_terminate(struct evdev_device *device)
device_unregister_capability(&device->base, device_unregister_capability(&device->base,
LIBINPUT_DEVICE_CAP_TOUCH); LIBINPUT_DEVICE_CAP_TOUCH);
} }
if (device->source)
libinput_remove_source(device->base.seat->libinput,
device->source);
if (device->mtdev)
mtdev_close_delete(device->mtdev);
close(device->fd);
list_remove(&device->base.link);
notify_removed_device(&device->base);
libinput_device_unref(&device->base);
} }
void void
@ -705,9 +731,6 @@ evdev_device_destroy(struct evdev_device *device)
if (dispatch) if (dispatch)
dispatch->interface->destroy(dispatch); dispatch->interface->destroy(dispatch);
if (device->mtdev)
mtdev_close_delete(device->mtdev);
close(device->fd);
free(device->devname); free(device->devname);
free(device->devnode); free(device->devnode);
free(device); free(device);

View file

@ -70,6 +70,7 @@ struct evdev_device {
struct libinput_source *source; struct libinput_source *source;
struct evdev_dispatch *dispatch; struct evdev_dispatch *dispatch;
char *output_name;
char *devnode; char *devnode;
char *devname; char *devname;
int fd; int fd;
@ -129,6 +130,11 @@ struct evdev_dispatch {
struct evdev_dispatch_interface *interface; struct evdev_dispatch_interface *interface;
}; };
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
int fd);
struct evdev_dispatch * struct evdev_dispatch *
evdev_touchpad_create(struct evdev_device *device); evdev_touchpad_create(struct evdev_device *device);
@ -141,11 +147,14 @@ evdev_device_led_update(struct evdev_device *device, enum libinput_led leds);
int int
evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size); evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size);
const char *
evdev_device_get_output(struct evdev_device *device);
void void
evdev_device_calibrate(struct evdev_device *device, float calibration[6]); evdev_device_calibrate(struct evdev_device *device, float calibration[6]);
void void
evdev_device_terminate(struct evdev_device *terminate); evdev_device_remove(struct evdev_device *device);
void void
evdev_device_destroy(struct evdev_device *device); evdev_device_destroy(struct evdev_device *device);

View file

@ -30,6 +30,8 @@ struct libinput {
int epoll_fd; int epoll_fd;
struct list source_destroy_list; struct list source_destroy_list;
struct list seat_list;
struct libinput_event **events; struct libinput_event **events;
size_t events_count; size_t events_count;
size_t events_len; size_t events_len;
@ -40,16 +42,32 @@ struct libinput {
void *user_data; void *user_data;
}; };
struct libinput_device { struct libinput_seat {
struct libinput *libinput; struct libinput *libinput;
struct list link;
struct list devices_list;
void *user_data;
int refcount;
char *name;
};
struct libinput_device {
struct libinput_seat *seat;
struct list link;
void *user_data; void *user_data;
int terminated; int terminated;
int refcount;
}; };
typedef void (*libinput_source_dispatch_t)(void *data); typedef void (*libinput_source_dispatch_t)(void *data);
struct libinput_source; struct libinput_source;
int
libinput_init(struct libinput *libinput,
const struct libinput_interface *interface,
void *user_data);
struct libinput_source * struct libinput_source *
libinput_add_fd(struct libinput *libinput, libinput_add_fd(struct libinput *libinput,
int fd, int fd,
@ -60,9 +78,33 @@ void
libinput_remove_source(struct libinput *libinput, libinput_remove_source(struct libinput *libinput,
struct libinput_source *source); struct libinput_source *source);
int
open_restricted(struct libinput *libinput,
const char *path, int flags);
void void
libinput_post_event(struct libinput *libinput, close_restricted(struct libinput *libinput, int fd);
struct libinput_event *event);
void
libinput_seat_init(struct libinput_seat *seat,
struct libinput *libinput,
const char *name);
void
libinput_device_init(struct libinput_device *device,
struct libinput_seat *seat);
void
notify_added_seat(struct libinput_seat *seat);
void
notify_removed_seat(struct libinput_seat *seat);
void
notify_added_device(struct libinput_device *device);
void
notify_removed_device(struct libinput_device *device);
void void
device_register_capability(struct libinput_device *device, device_register_capability(struct libinput_device *device,

View file

@ -30,8 +30,9 @@
#include <assert.h> #include <assert.h>
#include "libinput.h" #include "libinput.h"
#include "evdev.h"
#include "libinput-private.h" #include "libinput-private.h"
#include "evdev.h"
#include "udev-seat.h"
struct libinput_source { struct libinput_source {
libinput_source_dispatch_t dispatch; libinput_source_dispatch_t dispatch;
@ -40,6 +41,10 @@ struct libinput_source {
struct list link; struct list link;
}; };
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event);
struct libinput_source * struct libinput_source *
libinput_add_fd(struct libinput *libinput, libinput_add_fd(struct libinput *libinput,
int fd, int fd,
@ -80,25 +85,21 @@ libinput_remove_source(struct libinput *libinput,
list_insert(&libinput->source_destroy_list, &source->link); list_insert(&libinput->source_destroy_list, &source->link);
} }
LIBINPUT_EXPORT struct libinput * int
libinput_create(const struct libinput_interface *interface, void *user_data) libinput_init(struct libinput *libinput,
const struct libinput_interface *interface,
void *user_data)
{ {
struct libinput *libinput; libinput->epoll_fd = epoll_create1(EPOLL_CLOEXEC);;
if (libinput->epoll_fd < 0)
libinput = zalloc(sizeof *libinput); return -1;
if (!libinput)
return NULL;
list_init(&libinput->source_destroy_list);
libinput->interface = interface; libinput->interface = interface;
libinput->user_data = user_data; libinput->user_data = user_data;
list_init(&libinput->source_destroy_list);
list_init(&libinput->seat_list);
libinput->epoll_fd = epoll_create1(EPOLL_CLOEXEC);; return 0;
if (libinput->epoll_fd < 0)
return NULL;
return libinput;
} }
LIBINPUT_EXPORT void LIBINPUT_EXPORT void
@ -114,6 +115,88 @@ libinput_destroy(struct libinput *libinput)
free(libinput); free(libinput);
} }
int
open_restricted(struct libinput *libinput,
const char *path, int flags)
{
return libinput->interface->open_restricted(path,
flags,
libinput->user_data);
}
void
close_restricted(struct libinput *libinput, int fd)
{
return libinput->interface->close_restricted(fd, libinput->user_data);
}
void
libinput_seat_init(struct libinput_seat *seat,
struct libinput *libinput,
const char *name)
{
seat->refcount = 1;
seat->libinput = libinput;
seat->name = strdup(name);
list_init(&seat->devices_list);
}
LIBINPUT_EXPORT void
libinput_seat_ref(struct libinput_seat *seat)
{
seat->refcount++;
}
LIBINPUT_EXPORT void
libinput_seat_unref(struct libinput_seat *seat)
{
seat->refcount--;
if (seat->refcount == 0) {
free(seat->name);
udev_seat_destroy((struct udev_seat *) seat);
}
}
LIBINPUT_EXPORT void
libinput_seat_set_user_data(struct libinput_seat *seat, void *user_data)
{
seat->user_data = user_data;
}
LIBINPUT_EXPORT void *
libinput_seat_get_user_data(struct libinput_seat *seat)
{
return seat->user_data;
}
LIBINPUT_EXPORT const char *
libinput_seat_get_name(struct libinput_seat *seat)
{
return seat->name;
}
void
libinput_device_init(struct libinput_device *device,
struct libinput_seat *seat)
{
device->seat = seat;
device->refcount = 1;
}
LIBINPUT_EXPORT void
libinput_device_ref(struct libinput_device *device)
{
device->refcount++;
}
LIBINPUT_EXPORT void
libinput_device_unref(struct libinput_device *device)
{
device->refcount--;
if (device->refcount == 0)
evdev_device_destroy((struct evdev_device *) device);
}
LIBINPUT_EXPORT int LIBINPUT_EXPORT int
libinput_get_fd(struct libinput *libinput) libinput_get_fd(struct libinput *libinput)
{ {
@ -149,19 +232,114 @@ libinput_dispatch(struct libinput *libinput)
static void static void
init_event_base(struct libinput_event *event, init_event_base(struct libinput_event *event,
enum libinput_event_type type, enum libinput_event_type type,
struct libinput_device *device) union libinput_event_target target)
{ {
event->type = type; event->type = type;
event->device = device; event->target = target;
} }
static void
post_base_event(struct libinput *libinput,
enum libinput_event_type type,
struct libinput_event *event)
{
init_event_base(event, type,
(union libinput_event_target) { .libinput = libinput });
libinput_post_event(libinput, event);
}
#if 0
static void
post_seat_event(struct libinput_seat *seat,
enum libinput_event_type type,
struct libinput_event *event)
{
init_event_base(event, type,
(union libinput_event_target) { .seat = seat });
libinput_post_event(seat->libinput, event);
}
#endif
static void static void
post_device_event(struct libinput_device *device, post_device_event(struct libinput_device *device,
enum libinput_event_type type, enum libinput_event_type type,
struct libinput_event *event) struct libinput_event *event)
{ {
init_event_base(event, type, device); init_event_base(event, type,
libinput_post_event(device->libinput, event); (union libinput_event_target) { .device = device });
libinput_post_event(device->seat->libinput, event);
}
void
notify_added_seat(struct libinput_seat *seat)
{
struct libinput_event_added_seat *added_seat_event;
added_seat_event = malloc(sizeof *added_seat_event);
if (!added_seat_event)
return;
*added_seat_event = (struct libinput_event_added_seat) {
.seat = seat,
};
post_base_event(seat->libinput,
LIBINPUT_EVENT_ADDED_SEAT,
&added_seat_event->base);
}
void
notify_removed_seat(struct libinput_seat *seat)
{
struct libinput_event_removed_seat *removed_seat_event;
removed_seat_event = malloc(sizeof *removed_seat_event);
if (!removed_seat_event)
return;
*removed_seat_event = (struct libinput_event_removed_seat) {
.seat = seat,
};
post_base_event(seat->libinput,
LIBINPUT_EVENT_REMOVED_SEAT,
&removed_seat_event->base);
}
void
notify_added_device(struct libinput_device *device)
{
struct libinput_event_added_device *added_device_event;
added_device_event = malloc(sizeof *added_device_event);
if (!added_device_event)
return;
*added_device_event = (struct libinput_event_added_device) {
.device = device,
};
post_base_event(device->seat->libinput,
LIBINPUT_EVENT_ADDED_DEVICE,
&added_device_event->base);
}
void
notify_removed_device(struct libinput_device *device)
{
struct libinput_event_removed_device *removed_device_event;
removed_device_event = malloc(sizeof *removed_device_event);
if (!removed_device_event)
return;
*removed_device_event = (struct libinput_event_removed_device) {
.device = device,
};
post_base_event(device->seat->libinput,
LIBINPUT_EVENT_REMOVED_DEVICE,
&removed_device_event->base);
} }
void void
@ -340,7 +518,7 @@ touch_notify_touch(struct libinput_device *device,
&touch_event->base); &touch_event->base);
} }
void static void
libinput_post_event(struct libinput *libinput, libinput_post_event(struct libinput *libinput,
struct libinput_event *event) struct libinput_event *event)
{ {
@ -400,18 +578,28 @@ libinput_get_event(struct libinput *libinput)
return event; return event;
} }
LIBINPUT_EXPORT void LIBINPUT_EXPORT void *
libinput_device_terminate(struct libinput_device *device) libinput_get_user_data(struct libinput *libinput)
{ {
evdev_device_terminate((struct evdev_device *) device); return libinput->user_data;
device->terminated = 1; }
LIBINPUT_EXPORT int
libinput_resume(struct libinput *libinput)
{
return udev_input_enable((struct udev_input *) libinput);
} }
LIBINPUT_EXPORT void LIBINPUT_EXPORT void
libinput_device_destroy(struct libinput_device *device) libinput_suspend(struct libinput *libinput)
{ {
assert(device->terminated); udev_input_disable((struct udev_input *) libinput);
evdev_device_destroy((struct evdev_device *) device); }
LIBINPUT_EXPORT void
libinput_device_set_user_data(struct libinput_device *device, void *user_data)
{
device->user_data = user_data;
} }
LIBINPUT_EXPORT void * LIBINPUT_EXPORT void *
@ -420,6 +608,18 @@ libinput_device_get_user_data(struct libinput_device *device)
return device->user_data; return device->user_data;
} }
LIBINPUT_EXPORT const char *
libinput_device_get_output_name(struct libinput_device *device)
{
return evdev_device_get_output((struct evdev_device *) device);
}
LIBINPUT_EXPORT struct libinput_seat *
libinput_device_get_seat(struct libinput_device *device)
{
return device->seat;
}
LIBINPUT_EXPORT void LIBINPUT_EXPORT void
libinput_device_led_update(struct libinput_device *device, libinput_device_led_update(struct libinput_device *device,
enum libinput_led leds) enum libinput_led leds)

View file

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <libudev.h>
typedef int32_t li_fixed_t; typedef int32_t li_fixed_t;
@ -64,6 +65,11 @@ enum libinput_touch_type {
}; };
enum libinput_event_type { enum libinput_event_type {
LIBINPUT_EVENT_ADDED_SEAT = 0,
LIBINPUT_EVENT_REMOVED_SEAT,
LIBINPUT_EVENT_ADDED_DEVICE,
LIBINPUT_EVENT_REMOVED_DEVICE,
LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY = 200, LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY = 200,
LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY, LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY,
@ -77,8 +83,34 @@ enum libinput_event_type {
LIBINPUT_EVENT_TOUCH_TOUCH = 500, LIBINPUT_EVENT_TOUCH_TOUCH = 500,
}; };
union libinput_event_target {
struct libinput *libinput;
struct libinput_seat *seat;
struct libinput_device *device;
};
struct libinput_event { struct libinput_event {
enum libinput_event_type type; enum libinput_event_type type;
union libinput_event_target target;
};
struct libinput_event_added_seat {
struct libinput_event base;
struct libinput_seat *seat;
};
struct libinput_event_removed_seat {
struct libinput_event base;
struct libinput_seat *seat;
};
struct libinput_event_added_device {
struct libinput_event base;
struct libinput_device *device;
};
struct libinput_event_removed_device {
struct libinput_event base;
struct libinput_device *device; struct libinput_device *device;
}; };
@ -141,6 +173,9 @@ struct libinput_fd_handle;
typedef void (*libinput_fd_callback)(int fd, void *data); typedef void (*libinput_fd_callback)(int fd, void *data);
struct libinput_interface { struct libinput_interface {
int (*open_restricted)(const char *path, int flags, void *user_data);
void (*close_restricted)(int fd, void *user_data);
void (*get_current_screen_dimensions)(struct libinput_device *device, void (*get_current_screen_dimensions)(struct libinput_device *device,
int *width, int *width,
int *height, int *height,
@ -150,8 +185,15 @@ struct libinput_interface {
struct libinput; struct libinput;
struct libinput_device; struct libinput_device;
/*
* Base
*/
struct libinput * struct libinput *
libinput_create(const struct libinput_interface *interface, void *user_data); libinput_create_udev(const struct libinput_interface *interface,
void *user_data,
struct udev *udev,
const char *seat_id);
int int
libinput_get_fd(struct libinput *libinput); libinput_get_fd(struct libinput *libinput);
@ -162,24 +204,59 @@ libinput_dispatch(struct libinput *libinput);
struct libinput_event * struct libinput_event *
libinput_get_event(struct libinput *libinput); libinput_get_event(struct libinput *libinput);
void *
libinput_get_user_data(struct libinput *libinput);
int
libinput_resume(struct libinput *libinput);
void
libinput_suspend(struct libinput *libinput);
void void
libinput_destroy(struct libinput *libinput); libinput_destroy(struct libinput *libinput);
struct libinput_device * /*
libinput_device_create_evdev(struct libinput *libinput, * Seat
const char *devnode, */
int fd,
void *user_data);
void void
libinput_device_terminate(struct libinput_device *device); libinput_seat_ref(struct libinput_seat *seat);
void void
libinput_device_destroy(struct libinput_device *device); libinput_seat_unref(struct libinput_seat *seat);
void
libinput_seat_set_user_data(struct libinput_seat *seat, void *user_data);
void *
libinput_seat_get_user_data(struct libinput_seat *seat);
const char *
libinput_seat_get_name(struct libinput_seat *seat);
/*
* Device
*/
void
libinput_device_ref(struct libinput_device *device);
void
libinput_device_unref(struct libinput_device *device);
void
libinput_device_set_user_data(struct libinput_device *device, void *user_data);
void * void *
libinput_device_get_user_data(struct libinput_device *device); libinput_device_get_user_data(struct libinput_device *device);
const char *
libinput_device_get_output_name(struct libinput_device *device);
struct libinput_seat *
libinput_device_get_seat(struct libinput_device *device);
void void
libinput_device_led_update(struct libinput_device *device, libinput_device_led_update(struct libinput_device *device,
enum libinput_led leds); enum libinput_led leds);

View file

@ -23,12 +23,11 @@
#include "config.h" #include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include "compositor.h"
#include "launcher-util.h"
#include "evdev.h" #include "evdev.h"
#include "udev-seat.h" #include "udev-seat.h"
@ -36,16 +35,15 @@ static const char default_seat[] = "seat0";
static const char default_seat_name[] = "default"; static const char default_seat_name[] = "default";
static struct udev_seat * static struct udev_seat *
udev_seat_create(struct weston_compositor *c, const char *seat_name); udev_seat_create(struct udev_input *input, const char *seat_name);
static void static struct udev_seat *
udev_seat_destroy(struct udev_seat *seat); udev_seat_get_named(struct udev_input *input, const char *seat_name);
static int static int
device_added(struct udev_device *udev_device, struct udev_input *input) device_added(struct udev_device *udev_device, struct udev_input *input)
{ {
struct weston_compositor *c; struct libinput *libinput = &input->base;
struct evdev_device *device; struct evdev_device *device;
struct weston_output *output;
const char *devnode; const char *devnode;
const char *device_seat, *seat_name, *output_name; const char *device_seat, *seat_name, *output_name;
const char *calibration_values; const char *calibration_values;
@ -59,7 +57,6 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
if (strcmp(device_seat, input->seat_id)) if (strcmp(device_seat, input->seat_id))
return 0; return 0;
c = input->compositor;
devnode = udev_device_get_devnode(udev_device); devnode = udev_device_get_devnode(udev_device);
/* Search for matching logical seat */ /* Search for matching logical seat */
@ -67,7 +64,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
if (!seat_name) if (!seat_name)
seat_name = default_seat_name; seat_name = default_seat_name;
seat = udev_seat_get_named(c, seat_name); seat = udev_seat_get_named(input, seat_name);
if (seat == NULL) if (seat == NULL)
return -1; return -1;
@ -75,20 +72,20 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
/* Use non-blocking mode so that we can loop on read on /* Use non-blocking mode so that we can loop on read on
* evdev_device_data() until all events on the fd are * evdev_device_data() until all events on the fd are
* read. mtdev_get() also expects this. */ * read. mtdev_get() also expects this. */
fd = weston_launcher_open(c->launcher, devnode, O_RDWR | O_NONBLOCK); fd = open_restricted(libinput, devnode, O_RDWR | O_NONBLOCK);
if (fd < 0) { if (fd < 0) {
weston_log("opening input device '%s' failed.\n", devnode); log_info("opening input device '%s' failed.\n", devnode);
return 0; return 0;
} }
device = evdev_device_create(&seat->base, devnode, fd); device = evdev_device_create(&seat->base, devnode, fd);
if (device == EVDEV_UNHANDLED_DEVICE) { if (device == EVDEV_UNHANDLED_DEVICE) {
weston_launcher_close(c->launcher, fd); close_restricted(libinput, fd);
weston_log("not using input device '%s'.\n", devnode); log_info("not using input device '%s'.\n", devnode);
return 0; return 0;
} else if (device == NULL) { } else if (device == NULL) {
weston_launcher_close(c->launcher, fd); close_restricted(libinput, fd);
weston_log("failed to create input device '%s'.\n", devnode); log_info("failed to create input device '%s'.\n", devnode);
return 0; return 0;
} }
@ -105,7 +102,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
&device->abs.calibration[4], &device->abs.calibration[4],
&device->abs.calibration[5]) == 6) { &device->abs.calibration[5]) == 6) {
device->abs.apply_calibration = 1; device->abs.apply_calibration = 1;
weston_log ("Applying calibration: %f %f %f %f %f %f\n", log_info("Applying calibration: %f %f %f %f %f %f\n",
device->abs.calibration[0], device->abs.calibration[0],
device->abs.calibration[1], device->abs.calibration[1],
device->abs.calibration[2], device->abs.calibration[2],
@ -114,22 +111,9 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
device->abs.calibration[5]); device->abs.calibration[5]);
} }
wl_list_insert(seat->devices_list.prev, &device->link);
if (seat->base.output && seat->base.pointer)
weston_pointer_clamp(seat->base.pointer,
&seat->base.pointer->x,
&seat->base.pointer->y);
output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT"); output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
if (output_name) { if (output_name)
wl_list_for_each(output, &c->output_list, link) device->output_name = strdup(output_name);
if (strcmp(output->name, output_name) == 0)
device->output = output;
}
if (input->enabled == 1)
weston_seat_repick(&seat->base);
return 0; return 0;
} }
@ -141,8 +125,6 @@ udev_input_add_devices(struct udev_input *input, struct udev *udev)
struct udev_list_entry *entry; struct udev_list_entry *entry;
struct udev_device *device; struct udev_device *device;
const char *path, *sysname; const char *path, *sysname;
struct udev_seat *seat;
int devices_found = 0;
e = udev_enumerate_new(udev); e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "input"); udev_enumerate_add_match_subsystem(e, "input");
@ -167,31 +149,14 @@ udev_input_add_devices(struct udev_input *input, struct udev *udev)
} }
udev_enumerate_unref(e); udev_enumerate_unref(e);
wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
if (!wl_list_empty(&seat->devices_list))
devices_found = 1;
}
if (devices_found == 0) {
weston_log(
"warning: no input devices on entering Weston. "
"Possible causes:\n"
"\t- no permissions to read /dev/input/event*\n"
"\t- seats misconfigured "
"(Weston backend option 'seat', "
"udev device property ID_SEAT)\n");
return -1;
}
return 0; return 0;
} }
static int static void
evdev_udev_handler(int fd, uint32_t mask, void *data) evdev_udev_handler(void *data)
{ {
struct udev_input *input = data; struct udev_input *input = data;
struct libinput *libinput = &input->base;
struct udev_device *udev_device; struct udev_device *udev_device;
struct evdev_device *device, *next; struct evdev_device *device, *next;
const char *action; const char *action;
@ -200,7 +165,7 @@ evdev_udev_handler(int fd, uint32_t mask, void *data)
udev_device = udev_monitor_receive_device(input->udev_monitor); udev_device = udev_monitor_receive_device(input->udev_monitor);
if (!udev_device) if (!udev_device)
return 1; return;
action = udev_device_get_action(udev_device); action = udev_device_get_action(udev_device);
if (!action) if (!action)
@ -214,14 +179,14 @@ evdev_udev_handler(int fd, uint32_t mask, void *data)
} }
else if (!strcmp(action, "remove")) { else if (!strcmp(action, "remove")) {
devnode = udev_device_get_devnode(udev_device); devnode = udev_device_get_devnode(udev_device);
wl_list_for_each(seat, &input->compositor->seat_list, base.link) { list_for_each(seat, &input->base.seat_list, base.link) {
wl_list_for_each_safe(device, next, &seat->devices_list, link) list_for_each_safe(device, next,
&seat->base.devices_list, base.link)
if (!strcmp(device->devnode, devnode)) { if (!strcmp(device->devnode, devnode)) {
weston_log("input device %s, %s removed\n", log_info("input device %s, %s removed\n",
device->devname, device->devnode); device->devname, device->devnode);
weston_launcher_close(input->compositor->launcher, close_restricted(libinput, device->fd);
device->fd); evdev_device_remove(device);
evdev_device_destroy(device);
break; break;
} }
} }
@ -229,20 +194,17 @@ evdev_udev_handler(int fd, uint32_t mask, void *data)
out: out:
udev_device_unref(udev_device); udev_device_unref(udev_device);
return 0;
} }
int int
udev_input_enable(struct udev_input *input, struct udev *udev) udev_input_enable(struct udev_input *input)
{ {
struct wl_event_loop *loop; struct udev *udev = input->udev;
struct weston_compositor *c = input->compositor;
int fd; int fd;
input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (!input->udev_monitor) { if (!input->udev_monitor) {
weston_log("udev: failed to create the udev monitor\n"); log_info("udev: failed to create the udev monitor\n");
return -1; return -1;
} }
@ -250,16 +212,16 @@ udev_input_enable(struct udev_input *input, struct udev *udev)
"input", NULL); "input", NULL);
if (udev_monitor_enable_receiving(input->udev_monitor)) { if (udev_monitor_enable_receiving(input->udev_monitor)) {
weston_log("udev: failed to bind the udev monitor\n"); log_info("udev: failed to bind the udev monitor\n");
udev_monitor_unref(input->udev_monitor); udev_monitor_unref(input->udev_monitor);
return -1; return -1;
} }
loop = wl_display_get_event_loop(c->wl_display);
fd = udev_monitor_get_fd(input->udev_monitor); fd = udev_monitor_get_fd(input->udev_monitor);
input->udev_monitor_source = input->udev_monitor_source = libinput_add_fd(&input->base,
wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, fd,
evdev_udev_handler, input); evdev_udev_handler,
input);
if (!input->udev_monitor_source) { if (!input->udev_monitor_source) {
udev_monitor_unref(input->udev_monitor); udev_monitor_unref(input->udev_monitor);
return -1; return -1;
@ -268,8 +230,6 @@ udev_input_enable(struct udev_input *input, struct udev *udev)
if (udev_input_add_devices(input, udev) < 0) if (udev_input_add_devices(input, udev) < 0)
return -1; return -1;
input->enabled = 1;
return 0; return 0;
} }
@ -279,15 +239,12 @@ udev_input_remove_devices(struct udev_input *input)
struct evdev_device *device, *next; struct evdev_device *device, *next;
struct udev_seat *seat; struct udev_seat *seat;
wl_list_for_each(seat, &input->compositor->seat_list, base.link) { list_for_each(seat, &input->base.seat_list, base.link) {
wl_list_for_each_safe(device, next, &seat->devices_list, link) { list_for_each_safe(device, next,
weston_launcher_close(input->compositor->launcher, &seat->base.devices_list, base.link) {
device->fd); close_restricted(&input->base, device->fd);
evdev_device_destroy(device); evdev_device_remove(device);
} }
if (seat->base.keyboard)
notify_keyboard_focus_out(&seat->base);
} }
} }
@ -299,87 +256,92 @@ udev_input_disable(struct udev_input *input)
udev_monitor_unref(input->udev_monitor); udev_monitor_unref(input->udev_monitor);
input->udev_monitor = NULL; input->udev_monitor = NULL;
wl_event_source_remove(input->udev_monitor_source); libinput_remove_source(&input->base, input->udev_monitor_source);
input->udev_monitor_source = NULL; input->udev_monitor_source = NULL;
udev_input_remove_devices(input); udev_input_remove_devices(input);
} }
int
udev_input_init(struct udev_input *input, struct weston_compositor *c, struct udev *udev,
const char *seat_id)
{
memset(input, 0, sizeof *input);
input->seat_id = strdup(seat_id);
input->compositor = c;
if (udev_input_enable(input, udev) < 0)
goto err;
return 0;
err:
free(input->seat_id);
return -1;
}
void void
udev_input_destroy(struct udev_input *input) udev_input_destroy(struct udev_input *input)
{ {
struct udev_seat *seat, *next; struct libinput_seat *seat, *next;
udev_input_disable(input); udev_input_disable(input);
wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link) list_for_each_safe(seat, next, &input->base.seat_list, link) {
udev_seat_destroy(seat); notify_removed_seat(seat);
libinput_seat_unref(seat);
}
udev_unref(input->udev);
free(input->seat_id); free(input->seat_id);
} }
static void
drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
{
struct udev_seat *seat = (struct udev_seat *) seat_base;
struct evdev_device *device;
wl_list_for_each(device, &seat->devices_list, link)
evdev_led_update(device, leds);
}
static struct udev_seat * static struct udev_seat *
udev_seat_create(struct weston_compositor *c, const char *seat_name) udev_seat_create(struct udev_input *input, const char *seat_name)
{ {
struct udev_seat *seat; struct udev_seat *seat;
seat = zalloc(sizeof *seat); seat = zalloc(sizeof *seat);
if (!seat) if (!seat)
return NULL; return NULL;
weston_seat_init(&seat->base, c, seat_name);
seat->base.led_update = drm_led_update;
wl_list_init(&seat->devices_list); libinput_seat_init(&seat->base, &input->base, seat_name);
list_insert(&input->base.seat_list, &seat->base.link);
notify_added_seat(&seat->base);
return seat; return seat;
} }
static void void
udev_seat_destroy(struct udev_seat *seat) udev_seat_destroy(struct udev_seat *seat)
{ {
weston_seat_release(&seat->base); list_remove(&seat->base.link);
free(seat); free(seat);
} }
struct udev_seat * static struct udev_seat *
udev_seat_get_named(struct weston_compositor *c, const char *seat_name) udev_seat_get_named(struct udev_input *input, const char *seat_name)
{ {
struct udev_seat *seat; struct udev_seat *seat;
wl_list_for_each(seat, &c->seat_list, base.link) { list_for_each(seat, &input->base.seat_list, base.link) {
if (strcmp(seat->base.seat_name, seat_name) == 0) if (strcmp(seat->base.name, seat_name) == 0)
return seat; return seat;
} }
seat = udev_seat_create(c, seat_name); seat = udev_seat_create(input, seat_name);
if (!seat) if (!seat)
return NULL; return NULL;
return seat; return seat;
} }
LIBINPUT_EXPORT struct libinput *
libinput_create_udev(const struct libinput_interface *interface,
void *user_data,
struct udev *udev,
const char *seat_id)
{
struct udev_input *input;
input = zalloc(sizeof *input);
if (!input)
return NULL;
if (libinput_init(&input->base, interface, user_data) != 0) {
free(input);
return NULL;
}
input->udev = udev_ref(udev);
input->seat_id = strdup(seat_id);
if (udev_input_enable(input) < 0) {
udev_unref(udev);
libinput_destroy(&input->base);
free(input);
return NULL;
}
return &input->base;
}

View file

@ -27,30 +27,24 @@
#include <libudev.h> #include <libudev.h>
#include "compositor.h"
struct udev_seat { struct udev_seat {
struct weston_seat base; struct libinput_seat base;
struct wl_list devices_list; char *seat_name;
}; };
struct udev_input { struct udev_input {
struct libinput base;
struct udev *udev;
struct udev_monitor *udev_monitor; struct udev_monitor *udev_monitor;
struct wl_event_source *udev_monitor_source; struct libinput_source *udev_monitor_source;
char *seat_id; char *seat_id;
struct weston_compositor *compositor;
int enabled;
}; };
int udev_input_process_event(struct libinput_event);
int udev_input_enable(struct udev_input *input, struct udev *udev); int udev_input_enable(struct udev_input *input);
void udev_input_disable(struct udev_input *input); void udev_input_disable(struct udev_input *input);
int udev_input_init(struct udev_input *input,
struct weston_compositor *c,
struct udev *udev,
const char *seat_id);
void udev_input_destroy(struct udev_input *input); void udev_input_destroy(struct udev_input *input);
struct udev_seat *udev_seat_get_named(struct weston_compositor *c, void udev_seat_destroy(struct udev_seat *seat);
const char *seat_name);
#endif #endif