diff --git a/Makefile b/Makefile index 0c16050d..72e3f4dc 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ LDLIBS += $(shell pkg-config --libs libffi libdrm) all : wayland client -wayland_objs = wayland.o event-loop.o connection.o hash.o egl-compositor.o +wayland_objs = wayland.o event-loop.o connection.o hash.o input.o egl-compositor.o wayland : CFLAGS += -I../eagle wayland : LDLIBS += -L../eagle -leagle -ldl diff --git a/event-loop.c b/event-loop.c index f4311616..40f1c86a 100644 --- a/event-loop.c +++ b/event-loop.c @@ -31,6 +31,9 @@ wl_event_loop_add_fd(struct wl_event_loop *loop, struct epoll_event ep; source = malloc(sizeof *source); + if (source == NULL) + return NULL; + source->fd = fd; source->func = func; source->data = data; diff --git a/input.c b/input.c new file mode 100644 index 00000000..9df43071 --- /dev/null +++ b/input.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include + +#include + +#include "wayland.h" + +struct wl_input_device { + struct wl_object base; + struct wl_event_source *source; + struct wl_display *display; + int fd; + int tool; + int32_t x, y; +}; + +static const struct wl_method input_device_methods[] = { +}; + +static const struct wl_interface input_device_interface = { + "input_device", 1, + ARRAY_LENGTH(input_device_methods), + input_device_methods, +}; + +static void wl_input_device_data(int fd, uint32_t mask, void *data) +{ + struct wl_input_device *device = data; + struct input_event ev[8], *e, *end; + int len, value, dx, dy, absolute_event; + + dx = 0; + dy = 0; + absolute_event = 0; + + len = read(fd, &ev, sizeof ev); + if (len < 0 || len % sizeof e[0] != 0) { + /* FIXME: handle error... reopen device? */; + return; + } + + e = ev; + end = (void *) ev + len; + for (e = ev; e < end; e++) { + /* Get the signed value, earlier kernels had this as unsigned */ + value = e->value; + + switch (e->type) { + case EV_REL: + switch (e->code) { + case REL_X: + dx += value; + break; + + case REL_Y: + dy += value; + break; + } + + case EV_ABS: + absolute_event = 1; + switch (e->code) { + case ABS_X: + device->x = value; + break; + case ABS_Y: + device->y = value; + break; + } + + case EV_KEY: + if (value == 2) + break; + + switch (e->code) { + case BTN_TOUCH: + case BTN_TOOL_PEN: + case BTN_TOOL_RUBBER: + case BTN_TOOL_BRUSH: + case BTN_TOOL_PENCIL: + case BTN_TOOL_AIRBRUSH: + case BTN_TOOL_FINGER: + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + device->tool = value ? e->code : 0; + break; + + case BTN_LEFT: + wl_display_post_button_event(device->display, + &device->base, 0, value); + break; + + case BTN_RIGHT: + wl_display_post_button_event(device->display, + &device->base, 2, value); + break; + + case BTN_MIDDLE: + wl_display_post_button_event(device->display, + &device->base, 1, value); + break; + } + } + } + + if (dx != 0 || dy != 0) + wl_display_post_relative_event(device->display, + &device->base, dx, dy); + if (absolute_event && device->tool) + wl_display_post_absolute_event(device->display, + &device->base, + device->x, device->y); +} + +struct wl_object * +wl_input_device_create(struct wl_display *display, + const char *path, uint32_t id) +{ + struct wl_input_device *device; + struct wl_event_loop *loop; + + device = malloc(sizeof *device); + if (device == NULL) + return NULL; + + device->base.id = id; + device->base.interface = &input_device_interface; + device->display = display; + device->tool = 1; + + device->fd = open(path, O_RDONLY); + if (device->fd < 0) { + free(device); + fprintf(stderr, "couldn't create pointer for %s: %m\n", path); + return NULL; + } + + loop = wl_display_get_event_loop(display); + device->source = wl_event_loop_add_fd(loop, device->fd, + WL_EVENT_READABLE, + wl_input_device_data, device); + if (device->source == NULL) { + close(device->fd); + free(device); + return NULL; + } + + return &device->base; +} diff --git a/wayland-client.c b/wayland-client.c index e2b3b83e..a12e36b8 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -96,16 +96,14 @@ wl_display_get_fd(struct wl_display *display) } static void -handle_event(struct wl_connection *connection) +handle_event(struct wl_connection *connection, uint32_t opcode, uint32_t size) { - uint32_t p[2], opcode, size; + uint32_t p[4]; - wl_connection_copy(connection, p, sizeof p); - opcode = p[1] & 0xffff; - size = p[1] >> 16; - printf("signal from object %d, opcode %d, size %d\n", - p[0], opcode, size); - wl_connection_consume(connection, sizeof p); + wl_connection_copy(connection, p, size); + printf("signal from object %d, opcode %d, size %d, args: %d, %d\n", + p[0], opcode, size, p[2], p[3]); + wl_connection_consume(connection, size); } void @@ -125,7 +123,8 @@ wl_display_iterate(struct wl_display *display, uint32_t mask) if (len < size) break; - handle_event(display->connection); + handle_event(display->connection, opcode, size); + len -= size; } if (len < 0) { diff --git a/wayland.c b/wayland.c index 398f6377..0c1c75a1 100644 --- a/wayland.c +++ b/wayland.c @@ -12,8 +12,6 @@ #include "wayland.h" #include "connection.h" -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) @@ -51,6 +49,7 @@ struct wl_client { struct wl_event_source *source; struct wl_display *display; struct wl_list object_list; + struct wl_list link; }; struct wl_display { @@ -58,11 +57,17 @@ struct wl_display { struct wl_event_loop *loop; struct wl_hash objects; + struct wl_object *pointer; + struct wl_compositor *compositor; struct wl_compositor_interface *compositor_interface; struct wl_list surface_list; + struct wl_list client_list; uint32_t client_id_range; + + int32_t pointer_x; + int32_t pointer_y; }; struct wl_surface { @@ -403,6 +408,8 @@ wl_client_create(struct wl_display *display, int fd) advertise_object(client, &display->base); + wl_list_insert(display->client_list.prev, &client->link); + return client; } @@ -413,6 +420,8 @@ wl_client_destroy(struct wl_client *client) printf("disconnect from client %p\n", client); + wl_list_remove(&client->link); + while (client->object_list.next != &client->object_list) { ref = container_of(client->object_list.next, struct wl_object_ref, link); @@ -469,6 +478,21 @@ static const struct wl_interface display_interface = { ARRAY_LENGTH(display_events), display_events, }; +static const char input_device_file[] = + "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse"; + +static void +wl_display_create_input_devices(struct wl_display *display) +{ + display->pointer = wl_input_device_create(display, input_device_file, 1); + + if (display->pointer != NULL) + wl_hash_insert(&display->objects, display->pointer); + + display->pointer_x = 100; + display->pointer_y = 100; +} + struct wl_display * wl_display_create(void) { @@ -488,12 +512,81 @@ wl_display_create(void) display->base.interface = &display_interface; wl_hash_insert(&display->objects, &display->base); wl_list_init(&display->surface_list); + wl_list_init(&display->client_list); + + wl_display_create_input_devices(display); display->client_id_range = 256; /* Gah, arbitrary... */ return display; } +void +wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size) +{ + struct wl_client *client; + + client = container_of(display->client_list.next, + struct wl_client, link); + while (&client->link != &display->client_list) { + wl_connection_write(client->connection, data, size); + + client = container_of(client->link.next, + struct wl_client, link); + } +} + +#define WL_POINTER_MOTION 0 +#define WL_POINTER_BUTTON 1 + +void +wl_display_post_relative_event(struct wl_display *display, + struct wl_object *source, int dx, int dy) +{ + uint32_t p[4]; + + display->pointer_x += dx; + display->pointer_y += dy; + + p[0] = source->id; + p[1] = (sizeof p << 16) | WL_POINTER_MOTION; + p[2] = display->pointer_x; + p[3] = display->pointer_y; + + wl_display_send_event(display, p, sizeof p); +} + +void +wl_display_post_absolute_event(struct wl_display *display, + struct wl_object *source, int x, int y) +{ + uint32_t p[4]; + + display->pointer_x = x; + display->pointer_y = y; + + p[0] = source->id; + p[1] = (sizeof p << 16) | WL_POINTER_MOTION; + p[2] = display->pointer_x; + p[3] = display->pointer_y; + + wl_display_send_event(display, p, sizeof p); +} + +void +wl_display_post_button_event(struct wl_display *display, + struct wl_object *source, int button, int state) +{ + uint32_t p[4]; + + p[0] = source->id; + p[1] = (sizeof p << 16) | WL_POINTER_BUTTON; + p[2] = button; + p[3] = state; + + wl_display_send_event(display, p, sizeof p); +} + void wl_display_set_compositor(struct wl_display *display, struct wl_compositor *compositor) diff --git a/wayland.h b/wayland.h index 471ec7af..a7e80a41 100644 --- a/wayland.h +++ b/wayland.h @@ -3,6 +3,8 @@ #include +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + enum { WL_EVENT_READABLE = 0x01, WL_EVENT_WRITEABLE = 0x02 @@ -97,6 +99,19 @@ int wl_surface_iterator_next(struct wl_surface_iterator *iterator, struct wl_surface **surface); void wl_surface_iterator_destroy(struct wl_surface_iterator *iterator); +struct wl_object * +wl_input_device_create(struct wl_display *display, + const char *path, uint32_t id); +void +wl_display_post_relative_event(struct wl_display *display, + struct wl_object *source, int dx, int dy); +void +wl_display_post_absolute_event(struct wl_display *display, + struct wl_object *source, int x, int y); +void +wl_display_post_button_event(struct wl_display *display, + struct wl_object *source, int button, int state); + struct wl_compositor { struct wl_compositor_interface *interface; };