commit acec510

Michael Forney  ·  2017-03-11 22:42:29 +0000 UTC
parent bba112e
Make libinput a hard dependency

I am not interested in maintaining the direct evdev device handling, nor
implementing touchpad support. However, libinput has a hard libudev
dependency, even with the path-seat.

To resolve this, I branched libinput to remove the libinput dependency,
and made libinput a hard dependency in swc. Now, ENABLE_LIBINPUT
controls whether or not device hotplugging should be supported,
otherwise path-seat is used.
6 files changed,  +95, -587
+3, -3
 1@@ -14,14 +14,14 @@ Dependencies
 2 * wayland
 3 * wayland-protocols
 4 * libdrm
 5-* libevdev
 6+* libinput (see my [libinput repository](https://github.com/michaelforney/libinput)
 7+  if you don't want the libudev dependency)
 8 * libxkbcommon
 9 * pixman
10 * [wld](http://github.com/michaelforney/wld)
11 * linux\[>=3.12\] (for EVIOCREVOKE)
12 
13-For input hotplugging and touchpad support, the following is also required:
14-* libinput
15+For input hotplugging, the following is also required:
16 * libudev
17 
18 For XWayland support, the following are also required:
+1, -1
1@@ -18,6 +18,6 @@ CFLAGS          = -pipe
2 ENABLE_DEBUG    = 1
3 ENABLE_STATIC   = 1
4 ENABLE_SHARED   = 1
5-ENABLE_LIBINPUT = 1
6+ENABLE_LIBUDEV  = 1
7 ENABLE_XWAYLAND = 1
8 
+0, -355
  1@@ -1,355 +0,0 @@
  2-/* swc: libswc/evdev_device.c
  3- *
  4- * Copyright (c) 2013, 2014 Michael Forney
  5- *
  6- * Based in part upon evdev.c from weston, which is:
  7- *
  8- *     Copyright © 2010 Intel Corporation
  9- *
 10- * Permission is hereby granted, free of charge, to any person obtaining a copy
 11- * of this software and associated documentation files (the "Software"), to deal
 12- * in the Software without restriction, including without limitation the rights
 13- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14- * copies of the Software, and to permit persons to whom the Software is
 15- * furnished to do so, subject to the following conditions:
 16- *
 17- * The above copyright notice and this permission notice shall be included in
 18- * all copies or substantial portions of the Software.
 19- *
 20- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 26- * SOFTWARE.
 27- */
 28-
 29-#include "evdev_device.h"
 30-#include "event.h"
 31-#include "internal.h"
 32-#include "launch.h"
 33-#include "seat.h"
 34-#include "util.h"
 35-
 36-#include <errno.h>
 37-#include <fcntl.h>
 38-#include <libevdev/libevdev.h>
 39-#include <stdio.h>
 40-#include <stdlib.h>
 41-#include <string.h>
 42-#include <time.h>
 43-#include <unistd.h>
 44-
 45-#define AXIS_STEP_DISTANCE 10
 46-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 47-
 48-static inline uint32_t
 49-timeval_to_msec(struct timeval *time)
 50-{
 51-	return time->tv_sec * 1000 + time->tv_usec / 1000;
 52-}
 53-
 54-static void
 55-handle_key_event(struct evdev_device *device, struct input_event *ev)
 56-{
 57-	uint32_t time = timeval_to_msec(&ev->time);
 58-	uint32_t state;
 59-
 60-	if ((ev->code >= BTN_MISC && ev->code <= BTN_GEAR_UP) || ev->code >= BTN_TRIGGER_HAPPY) {
 61-		state = ev->value ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED;
 62-		device->handler->button(time, ev->code, state);
 63-		if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
 64-			/* qemu generates GEAR_UP/GEAR_DOWN events on scroll, so
 65-			 * pass those through as axis events. */
 66-			switch (ev->code) {
 67-			case BTN_GEAR_DOWN:
 68-				device->handler->axis(time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(AXIS_STEP_DISTANCE));
 69-				break;
 70-			case BTN_GEAR_UP:
 71-				device->handler->axis(time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(-AXIS_STEP_DISTANCE));
 72-				break;
 73-			}
 74-		}
 75-	} else {
 76-		state = ev->value ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED;
 77-		device->handler->key(time, ev->code, state);
 78-	}
 79-}
 80-
 81-static void
 82-handle_rel_event(struct evdev_device *device, struct input_event *ev)
 83-{
 84-	uint32_t time = timeval_to_msec(&ev->time);
 85-	uint32_t axis, amount;
 86-
 87-	if (!(device->capabilities & WL_SEAT_CAPABILITY_POINTER))
 88-		return;
 89-
 90-	switch (ev->code) {
 91-	case REL_X:
 92-		device->rel.dx += ev->value;
 93-		device->rel.pending = true;
 94-		return;
 95-	case REL_Y:
 96-		device->rel.dy += ev->value;
 97-		device->rel.pending = true;
 98-		return;
 99-	case REL_WHEEL:
100-		axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
101-		amount = -AXIS_STEP_DISTANCE * wl_fixed_from_int(ev->value);
102-		break;
103-	case REL_HWHEEL:
104-		axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
105-		amount = AXIS_STEP_DISTANCE * wl_fixed_from_int(ev->value);
106-		break;
107-	default:
108-		return;
109-	}
110-
111-	device->handler->axis(time, axis, amount);
112-}
113-
114-static void
115-handle_abs_event(struct evdev_device *device, struct input_event *ev)
116-{
117-	if (!(device->capabilities & WL_SEAT_CAPABILITY_POINTER))
118-		return;
119-
120-	switch (ev->code) {
121-	case ABS_X:
122-		device->abs.x = ev->value;
123-		device->abs.pending = true;
124-		break;
125-	case ABS_Y:
126-		device->abs.y = ev->value;
127-		device->abs.pending = true;
128-		break;
129-	}
130-}
131-
132-static void (*event_handlers[])(struct evdev_device *device, struct input_event *ev) = {
133-	[EV_KEY] = handle_key_event,
134-	[EV_REL] = handle_rel_event,
135-	[EV_ABS] = handle_abs_event,
136-};
137-
138-static bool
139-is_motion_event(struct input_event *ev)
140-{
141-	return (ev->type == EV_REL && (ev->code == REL_X || ev->code == REL_Y))
142-	    || (ev->type == EV_ABS && (ev->code == ABS_X || ev->code == ABS_Y));
143-}
144-
145-static void
146-handle_motion_events(struct evdev_device *device, uint32_t time)
147-{
148-	if (device->abs.pending) {
149-		int32_t x = device->abs.x - device->abs.info.x->minimum;
150-		int32_t max_x = device->abs.info.x->maximum - device->abs.info.x->minimum;
151-		int32_t y = device->abs.y - device->abs.info.y->minimum;
152-		int32_t max_y = device->abs.info.y->maximum - device->abs.info.y->minimum;
153-
154-		device->handler->absolute_motion(time, x, max_x, y, max_y);
155-		device->abs.pending = false;
156-	}
157-	if (device->rel.pending) {
158-		wl_fixed_t dx = wl_fixed_from_int(device->rel.dx);
159-		wl_fixed_t dy = wl_fixed_from_int(device->rel.dy);
160-
161-		device->handler->relative_motion(time, dx, dy);
162-		device->rel.pending = false;
163-		device->rel.dx = 0;
164-		device->rel.dy = 0;
165-	}
166-}
167-
168-static void
169-handle_event(struct evdev_device *device, struct input_event *ev)
170-{
171-	if (!is_motion_event(ev))
172-		handle_motion_events(device, timeval_to_msec(&ev->time));
173-
174-	if (ev->type < ARRAY_SIZE(event_handlers) && event_handlers[ev->type])
175-		event_handlers[ev->type](device, ev);
176-}
177-
178-static void
179-close_device(struct evdev_device *device)
180-{
181-	wl_event_source_remove(device->source);
182-	close(device->fd);
183-	device->source = NULL;
184-	device->fd = -1;
185-}
186-
187-static int
188-handle_data(int fd, uint32_t mask, void *data)
189-{
190-	struct evdev_device *device = data;
191-	struct input_event event;
192-	unsigned flags = device->needs_sync ? LIBEVDEV_READ_FLAG_FORCE_SYNC : LIBEVDEV_READ_FLAG_NORMAL;
193-	int ret;
194-
195-	device->needs_sync = false;
196-
197-	for (;;) {
198-		ret = libevdev_next_event(device->dev, flags, &event);
199-
200-		switch (ret) {
201-		case LIBEVDEV_READ_STATUS_SUCCESS:
202-			handle_event(device, &event);
203-			break;
204-		case LIBEVDEV_READ_STATUS_SYNC:
205-			while (ret == LIBEVDEV_READ_STATUS_SYNC) {
206-				ret = libevdev_next_event(device->dev, LIBEVDEV_READ_FLAG_SYNC, &event);
207-
208-				if (ret < 0)
209-					goto done;
210-
211-				handle_event(device, &event);
212-			}
213-			break;
214-		default:
215-			goto done;
216-		}
217-	}
218-
219-done:
220-	if (ret == -ENODEV)
221-		close_device(device);
222-
223-	handle_motion_events(device, timeval_to_msec(&event.time));
224-
225-	return 1;
226-}
227-
228-struct evdev_device *
229-evdev_device_new(const char *path, const struct evdev_device_handler *handler)
230-{
231-	struct evdev_device *device;
232-
233-	if (!(device = malloc(sizeof *device)))
234-		goto error0;
235-
236-	device->fd = launch_open_device(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
237-
238-	if (device->fd == -1) {
239-		ERROR("Failed to open input device at %s\n", path);
240-		goto error1;
241-	}
242-
243-	if (!(device->path = strdup(path)))
244-		goto error2;
245-
246-	if (libevdev_new_from_fd(device->fd, &device->dev) != 0) {
247-		ERROR("Failed to create libevdev device\n");
248-		goto error3;
249-	}
250-
251-	if (libevdev_set_clock_id(device->dev, CLOCK_MONOTONIC) != 0) {
252-		ERROR("Failed to set libevdev device to monotonic clock\n");
253-		goto error4;
254-	}
255-
256-	device->source = wl_event_loop_add_fd(swc.event_loop, device->fd, WL_EVENT_READABLE, handle_data, device);
257-
258-	if (!device->source) {
259-		ERROR("Failed to add event source\n");
260-		goto error4;
261-	}
262-
263-	DEBUG("Adding device %s\n", libevdev_get_name(device->dev));
264-
265-	device->needs_sync = false;
266-	device->handler = handler;
267-	device->capabilities = 0;
268-	device->abs.info.x = libevdev_get_abs_info(device->dev, ABS_X);
269-	device->abs.info.y = libevdev_get_abs_info(device->dev, ABS_Y);
270-	device->abs.pending = false;
271-	memset(&device->rel, 0, sizeof(device->rel));
272-
273-	if (libevdev_has_event_code(device->dev, EV_KEY, KEY_ENTER)) {
274-		device->capabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
275-		DEBUG("\tThis device is a keyboard\n");
276-	}
277-
278-	if (libevdev_has_event_code(device->dev, EV_REL, REL_X)
279-	 && libevdev_has_event_code(device->dev, EV_REL, REL_Y)
280-	 && libevdev_has_event_code(device->dev, EV_KEY, BTN_MOUSE))
281-	{
282-		device->capabilities |= WL_SEAT_CAPABILITY_POINTER;
283-		DEBUG("\tThis device is a pointer\n");
284-	}
285-
286-	if (libevdev_has_event_code(device->dev, EV_ABS, ABS_X)
287-	 && libevdev_has_event_code(device->dev, EV_ABS, ABS_Y)
288-	 && libevdev_has_event_code(device->dev, EV_KEY, BTN_MOUSE)
289-	 && !libevdev_has_event_code(device->dev, EV_KEY, BTN_TOOL_FINGER))
290-	{
291-		device->capabilities |= WL_SEAT_CAPABILITY_POINTER;
292-	}
293-
294-	/* XXX: touch devices */
295-
296-	return device;
297-
298-error4:
299-	libevdev_free(device->dev);
300-error3:
301-	free(device->path);
302-error2:
303-	close(device->fd);
304-error1:
305-	free(device);
306-error0:
307-	return NULL;
308-}
309-
310-void
311-evdev_device_destroy(struct evdev_device *device)
312-{
313-	if (device->source)
314-		close_device(device);
315-
316-	libevdev_free(device->dev);
317-	free(device->path);
318-	free(device);
319-}
320-
321-bool
322-evdev_device_reopen(struct evdev_device *device)
323-{
324-	if (device->source)
325-		close_device(device);
326-
327-	device->fd = launch_open_device(device->path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
328-
329-	if (device->fd == -1) {
330-		WARNING("Failed to reopen input device at %s: %s\n", device->path, strerror(errno));
331-		goto error0;
332-	}
333-
334-	if (libevdev_change_fd(device->dev, device->fd) == -1) {
335-		ERROR("Failed to update libevdev fd\n");
336-		goto error1;
337-	}
338-
339-	/* According to libevdev documentation, after changing the fd for the device,
340-	 * you should force a sync to bring it's state up to date. */
341-	device->needs_sync = true;
342-	device->source = wl_event_loop_add_fd(swc.event_loop, device->fd, WL_EVENT_READABLE, handle_data, device);
343-
344-	if (!device->source) {
345-		ERROR("Failed to create event source\n");
346-		goto error1;
347-	}
348-
349-	return true;
350-
351-error1:
352-	close(device->fd);
353-	device->fd = -1;
354-error0:
355-	return false;
356-}
+0, -78
 1@@ -1,78 +0,0 @@
 2-/* swc: libswc/evdev_device.h
 3- *
 4- * Copyright (c) 2013 Michael Forney
 5- *
 6- * Based in part upon evdev.h from weston, which is:
 7- *
 8- *     Copyright © 2011, 2012 Intel Corporation
 9- *
10- * Permission is hereby granted, free of charge, to any person obtaining a copy
11- * of this software and associated documentation files (the "Software"), to deal
12- * in the Software without restriction, including without limitation the rights
13- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14- * copies of the Software, and to permit persons to whom the Software is
15- * furnished to do so, subject to the following conditions:
16- *
17- * The above copyright notice and this permission notice shall be included in
18- * all copies or substantial portions of the Software.
19- *
20- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26- * SOFTWARE.
27- */
28-
29-#ifndef SWC_EVDEV_DEVICE_H
30-#define SWC_EVDEV_DEVICE_H
31-
32-#include <stdbool.h>
33-#include <linux/input.h>
34-#include <wayland-util.h>
35-
36-struct evdev_device;
37-struct wl_event_loop;
38-
39-struct evdev_device_handler {
40-	void (*key)(uint32_t time, uint32_t key, uint32_t state);
41-	void (*button)(uint32_t time, uint32_t key, uint32_t state);
42-	void (*axis)(uint32_t time, uint32_t axis, wl_fixed_t amount);
43-	void (*relative_motion)(uint32_t time, wl_fixed_t dx, wl_fixed_t dy);
44-	void (*absolute_motion)(uint32_t time, int32_t x, int32_t y, int32_t max_x, int32_t max_y);
45-};
46-
47-struct evdev_device {
48-	char *path;
49-	int fd;
50-	struct libevdev *dev;
51-	bool needs_sync;
52-
53-	const struct evdev_device_handler *handler;
54-
55-	struct {
56-		struct {
57-			const struct input_absinfo *x, *y;
58-		} info;
59-
60-		int32_t x, y;
61-		bool pending;
62-	} abs;
63-
64-	struct {
65-		int32_t dx, dy;
66-		bool pending;
67-	} rel;
68-
69-	uint32_t capabilities;
70-
71-	struct wl_event_source *source;
72-	struct wl_list link;
73-};
74-
75-struct evdev_device *evdev_device_new(const char *path, const struct evdev_device_handler *handler);
76-void evdev_device_destroy(struct evdev_device *device);
77-bool evdev_device_reopen(struct evdev_device *device);
78-
79-#endif
+4, -7
 1@@ -17,7 +17,7 @@ $(dir)_TARGETS +=                   \
 2     $(dir)/$(LIBSWC_LINK)
 3 endif
 4 
 5-$(dir)_PACKAGES := libdrm libevdev pixman-1 wayland-server wld xkbcommon
 6+$(dir)_PACKAGES := libdrm libinput pixman-1 wayland-server wld xkbcommon
 7 $(dir)_CFLAGS += -Iprotocol
 8 
 9 SWC_SOURCES =                       \
10@@ -59,11 +59,9 @@ SWC_SOURCES =                       \
11     protocol/wayland-drm-protocol.c \
12     protocol/xdg-shell-unstable-v5-protocol.c
13 
14-ifeq ($(ENABLE_LIBINPUT),1)
15-$(dir)_CFLAGS += -DENABLE_LIBINPUT
16-$(dir)_PACKAGES += libinput libudev
17-else
18-SWC_SOURCES += libswc/evdev_device.c
19+ifeq ($(ENABLE_LIBUDEV),1)
20+$(dir)_CFLAGS += -DENABLE_LIBUDEV
21+$(dir)_PACKAGES += libudev
22 endif
23 
24 ifeq ($(ENABLE_XWAYLAND),1)
25@@ -121,4 +119,3 @@ install-$(dir): $($(dir)_TARGETS:$(dir)/%=install-%) | $(DESTDIR)$(INCLUDEDIR)
26 CLEAN_FILES += $(SWC_SHARED_OBJECTS) $(SWC_STATIC_OBJECTS)
27 
28 include common.mk
29-
+87, -143
  1@@ -24,7 +24,6 @@
  2 #include "seat.h"
  3 #include "compositor.h"
  4 #include "data_device.h"
  5-#include "evdev_device.h"
  6 #include "event.h"
  7 #include "internal.h"
  8 #include "keyboard.h"
  9@@ -34,27 +33,28 @@
 10 #include "surface.h"
 11 #include "util.h"
 12 
 13-#include <errno.h>
 14 #include <dirent.h>
 15-#include <stdlib.h>
 16+#include <errno.h>
 17 #include <stdio.h>
 18+#include <stdlib.h>
 19 #include <string.h>
 20 #include <unistd.h>
 21-#ifdef ENABLE_LIBINPUT
 22+
 23+#include <libinput.h>
 24+#include <linux/input.h>
 25+#ifdef ENABLE_LIBUDEV
 26 # include <libudev.h>
 27-# include <libinput.h>
 28 #endif
 29 
 30 static struct {
 31 	char *name;
 32 	uint32_t capabilities;
 33 
 34-#ifdef ENABLE_LIBINPUT
 35-	struct udev *udev;
 36 	struct libinput *libinput;
 37 	struct wl_event_source *libinput_source;
 38-#else
 39-	struct wl_list devices;
 40+
 41+#ifdef ENABLE_LIBUDEV
 42+	struct udev *udev;
 43 #endif
 44 
 45 	struct wl_listener swc_listener;
 46@@ -73,41 +73,6 @@ const struct swc_seat swc_seat = {
 47 	.data_device = &seat.data_device,
 48 };
 49 
 50-static void
 51-handle_key(uint32_t time, uint32_t key, uint32_t state)
 52-{
 53-	keyboard_handle_key(&seat.keyboard, time, key, state);
 54-}
 55-
 56-static void
 57-handle_button(uint32_t time, uint32_t button, uint32_t state)
 58-{
 59-	pointer_handle_button(&seat.pointer, time, button, state);
 60-}
 61-
 62-static void
 63-handle_axis(uint32_t time, uint32_t axis, wl_fixed_t amount)
 64-{
 65-	pointer_handle_axis(&seat.pointer, time, axis, amount);
 66-}
 67-
 68-static void
 69-handle_relative_motion(uint32_t time, wl_fixed_t dx, wl_fixed_t dy)
 70-{
 71-	pointer_handle_relative_motion(&seat.pointer, time, dx, dy);
 72-}
 73-
 74-static void
 75-handle_absolute_motion(uint32_t time, int32_t x, int32_t max_x, int32_t y, int32_t max_y)
 76-{
 77-	struct screen *screen = wl_container_of(swc.screens.next, screen, link);
 78-	struct swc_rectangle *rect = &screen->base.geometry;
 79-	wl_fixed_t fx = wl_fixed_from_int(x * rect->width / max_x + rect->x);
 80-	wl_fixed_t fy = wl_fixed_from_int(y * rect->height / max_y + rect->y);
 81-
 82-	pointer_handle_absolute_motion(&seat.pointer, time, fx, fy);
 83-}
 84-
 85 static void
 86 handle_keyboard_focus_event(struct wl_listener *listener, void *data)
 87 {
 88@@ -151,30 +116,15 @@ static void
 89 handle_swc_event(struct wl_listener *listener, void *data)
 90 {
 91 	struct event *ev = data;
 92-#ifndef ENABLE_LIBINPUT
 93-	struct evdev_device *device, *next;
 94-#endif
 95 
 96 	switch (ev->type) {
 97 	case SWC_EVENT_DEACTIVATED:
 98-#ifdef ENABLE_LIBINPUT
 99 		libinput_suspend(seat.libinput);
100-#endif
101 		keyboard_reset(&seat.keyboard);
102 		break;
103 	case SWC_EVENT_ACTIVATED:
104-#ifdef ENABLE_LIBINPUT
105 		if (libinput_resume(seat.libinput) != 0)
106 			WARNING("Failed to resume libinput context\n");
107-#else
108-		/* Re-open all input devices */
109-		wl_list_for_each_safe (device, next, &seat.devices, link) {
110-			if (!evdev_device_reopen(device)) {
111-				wl_list_remove(&device->link);
112-				evdev_device_destroy(device);
113-			}
114-		}
115-#endif
116 		break;
117 	}
118 }
119@@ -235,7 +185,6 @@ update_capabilities(uint32_t capabilities)
120 		wl_seat_send_capabilities(resource, seat.capabilities);
121 }
122 
123-#ifdef ENABLE_LIBINPUT
124 static int
125 open_restricted(const char *path, int flags, void *user_data)
126 {
127@@ -273,19 +222,28 @@ device_capabilities(struct libinput_device *device)
128 static void
129 handle_libinput_axis_event(struct libinput_event_pointer *event, enum libinput_pointer_axis axis)
130 {
131-	double amount;
132+	wl_fixed_t amount;
133 
134 	if (!libinput_event_pointer_has_axis(event, axis))
135 		return;
136 
137-	amount = libinput_event_pointer_get_axis_value(event, axis);
138-	handle_axis(libinput_event_pointer_get_time(event), axis, wl_fixed_from_double(amount));
139+	amount = wl_fixed_from_double(libinput_event_pointer_get_axis_value(event, axis));
140+	pointer_handle_axis(&seat.pointer, libinput_event_pointer_get_time(event), axis, amount);
141 }
142 
143 static int
144 handle_libinput_data(int fd, uint32_t mask, void *data)
145 {
146+	struct screen *screen;
147+	struct swc_rectangle *rect;
148 	struct libinput_event *generic_event;
149+	struct libinput_device *device;
150+	union {
151+		struct libinput_event_keyboard *k;
152+		struct libinput_event_pointer *p;
153+	} event;
154+	wl_fixed_t x, y;
155+	uint32_t time, key, state;
156 
157 	if (libinput_dispatch(seat.libinput) != 0) {
158 		WARNING("libinput_dispatch failed: %s\n", strerror(errno));
159@@ -294,49 +252,57 @@ handle_libinput_data(int fd, uint32_t mask, void *data)
160 
161 	while ((generic_event = libinput_get_event(seat.libinput))) {
162 		switch (libinput_event_get_type(generic_event)) {
163-		case LIBINPUT_EVENT_DEVICE_ADDED: {
164-			struct libinput_device *device;
165-
166+		case LIBINPUT_EVENT_DEVICE_ADDED:
167 			device = libinput_event_get_device(generic_event);
168 			update_capabilities(device_capabilities(device));
169 			break;
170-		}
171-		case LIBINPUT_EVENT_KEYBOARD_KEY: {
172-			struct libinput_event_keyboard *event;
173-
174-			event = libinput_event_get_keyboard_event(generic_event);
175-			handle_key(libinput_event_keyboard_get_time(event),
176-			           libinput_event_keyboard_get_key(event),
177-			           libinput_event_keyboard_get_key_state(event));
178+		case LIBINPUT_EVENT_KEYBOARD_KEY:
179+			event.k = libinput_event_get_keyboard_event(generic_event);
180+			time = libinput_event_keyboard_get_time(event.k);
181+			key = libinput_event_keyboard_get_key(event.k);
182+			state = libinput_event_keyboard_get_key_state(event.k);
183+			keyboard_handle_key(&seat.keyboard, time, key, state);
184 			break;
185-		}
186-		case LIBINPUT_EVENT_POINTER_MOTION: {
187-			struct libinput_event_pointer *event;
188-			wl_fixed_t dx, dy;
189-
190-			event = libinput_event_get_pointer_event(generic_event);
191-			dx = wl_fixed_from_double(libinput_event_pointer_get_dx(event));
192-			dy = wl_fixed_from_double(libinput_event_pointer_get_dy(event));
193-			handle_relative_motion(libinput_event_pointer_get_time(event), dx, dy);
194+		case LIBINPUT_EVENT_POINTER_MOTION:
195+			event.p = libinput_event_get_pointer_event(generic_event);
196+			time = libinput_event_pointer_get_time(event.p);
197+			x = wl_fixed_from_double(libinput_event_pointer_get_dx(event.p));
198+			y = wl_fixed_from_double(libinput_event_pointer_get_dy(event.p));
199+			pointer_handle_relative_motion(&seat.pointer, time, x, y);
200 			break;
201-		}
202-		case LIBINPUT_EVENT_POINTER_BUTTON: {
203-			struct libinput_event_pointer *event;
204-
205-			event = libinput_event_get_pointer_event(generic_event);
206-			handle_button(libinput_event_pointer_get_time(event),
207-			              libinput_event_pointer_get_button(event),
208-			              libinput_event_pointer_get_button_state(event));
209+		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
210+			screen = wl_container_of(swc.screens.next, screen, link);
211+			rect = &screen->base.geometry;
212+			event.p = libinput_event_get_pointer_event(generic_event);
213+			time = libinput_event_pointer_get_time(event.p);
214+			x = wl_fixed_from_double(libinput_event_pointer_get_absolute_x_transformed(event.p, rect->width));
215+			y = wl_fixed_from_double(libinput_event_pointer_get_absolute_y_transformed(event.p, rect->height));
216+			pointer_handle_absolute_motion(&seat.pointer, time, x, y);
217 			break;
218-		}
219-		case LIBINPUT_EVENT_POINTER_AXIS: {
220-			struct libinput_event_pointer *event;
221-
222-			event = libinput_event_get_pointer_event(generic_event);
223-			handle_libinput_axis_event(event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
224-			handle_libinput_axis_event(event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
225+		case LIBINPUT_EVENT_POINTER_BUTTON:
226+			event.p = libinput_event_get_pointer_event(generic_event);
227+			time = libinput_event_pointer_get_time(event.p);
228+			key = libinput_event_pointer_get_button(event.p);
229+			state = libinput_event_pointer_get_button_state(event.p);
230+			pointer_handle_button(&seat.pointer, time, key, state);
231+			if (state == LIBINPUT_BUTTON_STATE_PRESSED) {
232+		                /* qemu generates GEAR_UP/GEAR_DOWN events on scroll, so pass
233+				 * those through as axis events. */
234+				switch (key) {
235+				case BTN_GEAR_DOWN:
236+					pointer_handle_axis(&seat.pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(10));
237+					break;
238+				case BTN_GEAR_UP:
239+					pointer_handle_axis(&seat.pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(-10));
240+					break;
241+				}
242+			}
243+			break;
244+		case LIBINPUT_EVENT_POINTER_AXIS:
245+			event.p = libinput_event_get_pointer_event(generic_event);
246+			handle_libinput_axis_event(event.p, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
247+			handle_libinput_axis_event(event.p, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
248 			break;
249-		}
250 		default:
251 			break;
252 		}
253@@ -350,22 +316,28 @@ handle_libinput_data(int fd, uint32_t mask, void *data)
254 bool
255 initialize_libinput(const char *seat_name)
256 {
257+#ifdef ENABLE_LIBUDEV
258 	if (!(seat.udev = udev_new())) {
259 		ERROR("Could not create udev context\n");
260 		goto error0;
261 	}
262 
263 	seat.libinput = libinput_udev_create_context(&libinput_interface, NULL, seat.udev);
264+#else
265+	seat.libinput = libinput_path_create_context(&libinput_interface, NULL);
266+#endif
267 
268 	if (!seat.libinput) {
269 		ERROR("Could not create libinput context\n");
270 		goto error1;
271 	}
272 
273+#ifdef ENABLE_LIBUDEV
274 	if (libinput_udev_assign_seat(seat.libinput, seat_name) != 0) {
275 		ERROR("Failed to assign seat to libinput context\n");
276 		goto error2;
277 	}
278+#endif
279 
280 	seat.libinput_source = wl_event_loop_add_fd
281 		(swc.event_loop, libinput_get_fd(seat.libinput), WL_EVENT_READABLE,
282@@ -384,41 +356,14 @@ initialize_libinput(const char *seat_name)
283 error2:
284 	libinput_unref(seat.libinput);
285 error1:
286+#ifdef ENABLE_LIBUDEV
287 	udev_unref(seat.udev);
288 error0:
289+#endif
290 	return false;
291 }
292 
293-void
294-finalize_libinput(void)
295-{
296-	wl_event_source_remove(seat.libinput_source);
297-	libinput_unref(seat.libinput);
298-	udev_unref(seat.udev);
299-}
300-#else
301-const static struct evdev_device_handler evdev_handler = {
302-	.key = handle_key,
303-	.button = handle_button,
304-	.axis = handle_axis,
305-	.relative_motion = handle_relative_motion,
306-	.absolute_motion = handle_absolute_motion,
307-};
308-
309-static void
310-add_device(const char *path)
311-{
312-	struct evdev_device *device;
313-
314-	if (!(device = evdev_device_new(path, &evdev_handler))) {
315-		ERROR("Could not create evdev device\n");
316-		return;
317-	}
318-
319-	update_capabilities(device->capabilities);
320-	wl_list_insert(&seat.devices, &device->link);
321-}
322-
323+#ifndef ENABLE_LIBUDEV
324 static int
325 select_device(const struct dirent *entry)
326 {
327@@ -430,20 +375,23 @@ static bool
328 add_devices(void)
329 {
330 	struct dirent **devices;
331-	int i, num_devices;
332+	int i, n;
333 	char path[64];
334+	struct libinput_device *device;
335 
336-	num_devices = scandir("/dev/input", &devices, &select_device, &alphasort);
337+	n = scandir("/dev/input", &devices, &select_device, &alphasort);
338 
339-	if (num_devices == -1) {
340+	if (n == -1) {
341 		ERROR("Failed to scan /dev/input for event devices\n");
342 		return false;
343 	}
344 
345-	for (i = 0; i < num_devices; ++i) {
346+	for (i = 0; i < n; ++i) {
347 		snprintf(path, sizeof path, "/dev/input/%s", devices[i]->d_name);
348 		free(devices[i]);
349-		add_device(path);
350+		device = libinput_path_add_device(seat.libinput, path);
351+		if (device)
352+			update_capabilities(device_capabilities(device));
353 	}
354 
355 	free(devices);
356@@ -489,12 +437,10 @@ seat_initialize(const char *seat_name)
357 		goto error4;
358 	}
359 
360-#ifdef ENABLE_LIBINPUT
361 	if (!initialize_libinput(seat.name))
362 		goto error5;
363-#else
364-	wl_list_init(&seat.devices);
365 
366+#ifndef ENABLE_LIBUDEV
367 	if (!add_devices())
368 		goto error5;
369 #endif
370@@ -518,12 +464,10 @@ error0:
371 void
372 seat_finalize(void)
373 {
374-#ifdef ENABLE_LIBINPUT
375-	finalize_libinput();
376-#else
377-	struct evdev_device *device, *tmp;
378-	wl_list_for_each_safe (device, tmp, &seat.devices, link)
379-		evdev_device_destroy(device);
380+	wl_event_source_remove(seat.libinput_source);
381+	libinput_unref(seat.libinput);
382+#ifdef ENABLE_LIBUDEV
383+	udev_unref(seat.udev);
384 #endif
385 
386 	pointer_finalize(&seat.pointer);