diff --git a/compositor/evdev.c b/compositor/evdev.c
index 11f7f5e4..c065b33c 100644
--- a/compositor/evdev.c
+++ b/compositor/evdev.c
@@ -37,6 +37,8 @@ struct evdev_input {
 	char *seat_id;
 };
 
+#define MAX_SLOTS 10
+
 struct evdev_input_device {
 	struct evdev_input *master;
 	struct wl_list link;
@@ -47,8 +49,21 @@ struct evdev_input_device {
 	struct {
 		int min_x, max_x, min_y, max_y;
 		int old_x, old_y, reset_x, reset_y;
-		int slot_mt;
+		int32_t x, y;
 	} abs;
+
+	struct {
+		int slot;
+		int32_t x[MAX_SLOTS];
+		int32_t y[MAX_SLOTS];
+	} mt;
+
+	struct {
+		int dx, dy;
+	} rel;
+
+	int type; /* event type flags */
+
 	int is_touchpad, is_mt;
 };
 
@@ -59,13 +74,6 @@ struct evdev_input_device {
 #define EVDEV_ABSOLUTE_MT_UP		(1 << 3)
 #define EVDEV_RELATIVE_MOTION		(1 << 4)
 
-struct evdev_motion_accumulator {
-	int x, y;
-	int dx, dy;
-	int mt_x, mt_y;
-	int type; /* event type flags */
-};
-
 static inline void
 evdev_process_key(struct evdev_input_device *device,
                         struct input_event *e, int time)
@@ -121,63 +129,66 @@ evdev_process_key(struct evdev_input_device *device,
 
 static void
 evdev_process_touch(struct evdev_input_device *device,
-		    struct input_event *e, int time,
-		    struct evdev_motion_accumulator *accum)
+		    struct input_event *e)
 {
 	const int screen_width = device->output->current->width;
 	const int screen_height = device->output->current->height;
 
 	switch (e->code) {
 	case ABS_MT_SLOT:
-		device->abs.slot_mt = e->value;
+		device->mt.slot = e->value;
 		break;
 	case ABS_MT_TRACKING_ID:
 		if (e->value >= 0)
-			accum->type |= EVDEV_ABSOLUTE_MT_DOWN;
+			device->type |= EVDEV_ABSOLUTE_MT_DOWN;
 		else
-			accum->type |= EVDEV_ABSOLUTE_MT_UP;
+			device->type |= EVDEV_ABSOLUTE_MT_UP;
 		break;
 	case ABS_MT_POSITION_X:
-		accum->mt_x = (e->value - device->abs.min_x) * screen_width /
+		device->mt.x[device->mt.slot] =
+			(e->value - device->abs.min_x) * screen_width /
 			(device->abs.max_x - device->abs.min_x) +
 			device->output->x;
-		accum->type |= EVDEV_ABSOLUTE_MT_MOTION;
+		device->type |= EVDEV_ABSOLUTE_MT_MOTION;
 		break;
 	case ABS_MT_POSITION_Y:
-		accum->mt_y = (e->value - device->abs.min_y) * screen_height /
+		device->mt.y[device->mt.slot] =
+			(e->value - device->abs.min_y) * screen_height /
 			(device->abs.max_y - device->abs.min_y) +
 			device->output->y;
-		accum->type |= EVDEV_ABSOLUTE_MT_MOTION;
+		device->type |= EVDEV_ABSOLUTE_MT_MOTION;
 		break;
 	}
 }
 
 static inline void
 evdev_process_absolute_motion(struct evdev_input_device *device,
-		struct input_event *e, struct evdev_motion_accumulator *accum)
+			      struct input_event *e)
 {
 	const int screen_width = device->output->current->width;
 	const int screen_height = device->output->current->height;
 
 	switch (e->code) {
 	case ABS_X:
-		accum->x = (e->value - device->abs.min_x) * screen_width /
+		device->abs.x =
+			(e->value - device->abs.min_x) * screen_width /
 			(device->abs.max_x - device->abs.min_x) +
 			device->output->x;
-		accum->type |= EVDEV_ABSOLUTE_MOTION;
+		device->type |= EVDEV_ABSOLUTE_MOTION;
 		break;
 	case ABS_Y:
-		accum->y = (e->value - device->abs.min_y) * screen_height /
+		device->abs.y =
+			(e->value - device->abs.min_y) * screen_height /
 			(device->abs.max_y - device->abs.min_y) +
 			device->output->y;
-		accum->type |= EVDEV_ABSOLUTE_MOTION;
+		device->type |= EVDEV_ABSOLUTE_MOTION;
 		break;
 	}
 }
 
 static inline void
 evdev_process_absolute_motion_touchpad(struct evdev_input_device *device,
-		struct input_event *e, struct evdev_motion_accumulator *accum)
+				       struct input_event *e)
 {
 	/* FIXME: Make this configurable somehow. */
 	const int touchpad_speed = 700;
@@ -188,56 +199,57 @@ evdev_process_absolute_motion_touchpad(struct evdev_input_device *device,
 		if (device->abs.reset_x)
 			device->abs.reset_x = 0;
 		else {
-			accum->dx = (e->value - device->abs.old_x) *
+			device->rel.dx =
+				(e->value - device->abs.old_x) *
 				touchpad_speed /
 				(device->abs.max_x - device->abs.min_x);
 		}
 		device->abs.old_x = e->value;
-		accum->type |= EVDEV_RELATIVE_MOTION;
+		device->type |= EVDEV_RELATIVE_MOTION;
 		break;
 	case ABS_Y:
 		e->value -= device->abs.min_y;
 		if (device->abs.reset_y)
 			device->abs.reset_y = 0;
 		else {
-			accum->dy = (e->value - device->abs.old_y) *
+			device->rel.dy =
+				(e->value - device->abs.old_y) *
 				touchpad_speed /
 				/* maybe use x size here to have the same scale? */
 				(device->abs.max_y - device->abs.min_y);
 		}
 		device->abs.old_y = e->value;
-		accum->type |= EVDEV_RELATIVE_MOTION;
+		device->type |= EVDEV_RELATIVE_MOTION;
 		break;
 	}
 }
 
 static inline void
-evdev_process_relative_motion(struct input_event *e,
-			      struct evdev_motion_accumulator *accum)
+evdev_process_relative_motion(struct evdev_input_device *device,
+			      struct input_event *e)
 {
 	switch (e->code) {
 	case REL_X:
-		accum->dx += e->value;
-		accum->type |= EVDEV_RELATIVE_MOTION;
+		device->rel.dx += e->value;
+		device->type |= EVDEV_RELATIVE_MOTION;
 		break;
 	case REL_Y:
-		accum->dy += e->value;
-		accum->type |= EVDEV_RELATIVE_MOTION;
+		device->rel.dy += e->value;
+		device->type |= EVDEV_RELATIVE_MOTION;
 		break;
 	}
 }
 
 static inline void
 evdev_process_absolute(struct evdev_input_device *device,
-		struct input_event *e, int time,
-		struct evdev_motion_accumulator *accum)
+		       struct input_event *e)
 {
 	if (device->is_touchpad) {
-		evdev_process_absolute_motion_touchpad(device, e, accum);
+		evdev_process_absolute_motion_touchpad(device, e);
 	} else if (device->is_mt) {
-		evdev_process_touch(device, e, time, accum);
+		evdev_process_touch(device, e);
 	} else {
-		evdev_process_absolute_motion(device, e, accum);
+		evdev_process_absolute_motion(device, e);
 	}
 }
 
@@ -265,39 +277,48 @@ is_motion_event(struct input_event *e)
 }
 
 static void
-evdev_flush_motion(struct wl_input_device *device, uint32_t time,
-		   struct evdev_motion_accumulator *accum, int slot_mt)
+evdev_flush_motion(struct evdev_input_device *device, uint32_t time)
 {
-	if (!accum->type)
+	struct wl_input_device *master =
+		&device->master->base.input_device;
+
+	if (!device->type)
 		return;
 
-	if (accum->type & EVDEV_RELATIVE_MOTION) {
-		notify_motion(device, time,
-			      device->x + accum->dx, device->y + accum->dy);
-		accum->type &= ~EVDEV_RELATIVE_MOTION;
-		accum->dx = 0;
-		accum->dy = 0;
+	if (device->type & EVDEV_RELATIVE_MOTION) {
+		notify_motion(master, time,
+			      master->x + device->rel.dx,
+			      master->y + device->rel.dy);
+		device->type &= ~EVDEV_RELATIVE_MOTION;
+		device->rel.dx = 0;
+		device->rel.dy = 0;
 	}
-	if (accum->type & EVDEV_ABSOLUTE_MT_DOWN) {
-		notify_touch(device, time, slot_mt, accum->mt_x, accum->mt_y,
+	if (device->type & EVDEV_ABSOLUTE_MT_DOWN) {
+		notify_touch(master, time,
+			     device->mt.slot,
+			     device->mt.x[device->mt.slot],
+			     device->mt.y[device->mt.slot],
 			     WL_INPUT_DEVICE_TOUCH_DOWN);
-		accum->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
-		accum->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
+		device->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
+		device->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
 	}
-	if (accum->type & EVDEV_ABSOLUTE_MT_MOTION) {
-		notify_touch(device, time, slot_mt, accum->mt_x, accum->mt_y,
-				WL_INPUT_DEVICE_TOUCH_MOTION);
-		accum->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
-		accum->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
+	if (device->type & EVDEV_ABSOLUTE_MT_MOTION) {
+		notify_touch(master, time,
+			     device->mt.slot,
+			     device->mt.x[device->mt.slot],
+			     device->mt.y[device->mt.slot],
+			     WL_INPUT_DEVICE_TOUCH_MOTION);
+		device->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
+		device->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
 	}
-	if (accum->type & EVDEV_ABSOLUTE_MT_UP) {
-		notify_touch(device, time, slot_mt, 0, 0,
+	if (device->type & EVDEV_ABSOLUTE_MT_UP) {
+		notify_touch(master, time, device->mt.slot, 0, 0,
 			     WL_INPUT_DEVICE_TOUCH_UP);
-		accum->type &= ~EVDEV_ABSOLUTE_MT_UP;
+		device->type &= ~EVDEV_ABSOLUTE_MT_UP;
 	}
-	if (accum->type & EVDEV_ABSOLUTE_MOTION) {
-		notify_motion(device, time, accum->x, accum->y);
-		accum->type &= ~EVDEV_ABSOLUTE_MOTION;
+	if (device->type & EVDEV_ABSOLUTE_MOTION) {
+		notify_motion(master, time, device->abs.x, device->abs.y);
+		device->type &= ~EVDEV_ABSOLUTE_MOTION;
 	}
 }
 
@@ -308,7 +329,6 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 	struct evdev_input_device *device = data;
 	struct input_event ev[8], *e, *end;
 	int len;
-	struct evdev_motion_accumulator accumulator;
 	uint32_t time = 0;
 
 	ec = device->master->base.compositor;
@@ -321,10 +341,6 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 		return 1;
 	}
 
-	accumulator.type = 0;
-	accumulator.mt_x = accumulator.x = device->master->base.input_device.x;
-	accumulator.mt_y = accumulator.y = device->master->base.input_device.y;
-
 	e = ev;
 	end = (void *) ev + len;
 	for (e = ev; e < end; e++) {
@@ -334,15 +350,13 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 		 * forwarded to the compositor, so we accumulate motion
 		 * events and send as a bunch */
 		if (!is_motion_event(e))
-			evdev_flush_motion(&device->master->base.input_device,
-					   time, &accumulator,
-					   device->abs.slot_mt);
+			evdev_flush_motion(device, time);
 		switch (e->type) {
 		case EV_REL:
-			evdev_process_relative_motion(e, &accumulator);
+			evdev_process_relative_motion(device, e);
 			break;
 		case EV_ABS:
-			evdev_process_absolute(device, e, time, &accumulator);
+			evdev_process_absolute(device, e);
 			break;
 		case EV_KEY:
 			evdev_process_key(device, e, time);
@@ -350,8 +364,7 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 		}
 	}
 
-	evdev_flush_motion(&device->master->base.input_device, time,
-			   &accumulator, device->abs.slot_mt);
+	evdev_flush_motion(device, time);
 
 	return 1;
 }
@@ -397,7 +410,7 @@ evdev_configure_device(struct evdev_input_device *device)
 		}
 		if (TEST_BIT(abs_bits, ABS_MT_SLOT)) {
 			device->is_mt = 1;
-			device->abs.slot_mt = 0;
+			device->mt.slot = 0;
 		}
 	}
 	if (TEST_BIT(ev_bits, EV_KEY)) {
@@ -438,7 +451,9 @@ evdev_input_device_create(struct evdev_input *master,
 	device->is_touchpad = 0;
 	device->is_mt = 0;
 	device->devnode = strdup(path);
-	device->abs.slot_mt = -1;
+	device->mt.slot = -1;
+	device->rel.dx = 0;
+	device->rel.dy = 0;
 
 	device->fd = open(path, O_RDONLY);
 	if (device->fd < 0)