compositor: Don't let pointers get outside of an output on mode switch

When an output suffers a mode switch, it is possible that a pointer
was inside the old output area but falls outside of it with the new
size. In that case, move the cursor to the output's bottom-right
corner. Otherwise, there's a crash in clip_pointer_motion().
diff --git a/src/compositor.c b/src/compositor.c
index 567105e..e556766 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -90,6 +90,8 @@
 WL_EXPORT int
 weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode)
 {
+	struct weston_seat *seat;
+	pixman_region32_t old_output_region;
 	int ret;
 
 	if (!output->switch_mode)
@@ -99,6 +101,9 @@
 	if (ret < 0)
 		return ret;
 
+	pixman_region32_init(&old_output_region);
+	pixman_region32_copy(&old_output_region, &output->region);
+
 	/* Update output region and transformation matrix */
 	weston_output_transform_init(output, output->transform);
 
@@ -108,6 +113,35 @@
 
 	weston_output_update_matrix(output);
 
+	/* If a pointer falls outside the outputs new geometry, move it to its
+	 * lower-right corner */
+	wl_list_for_each(seat, &output->compositor->seat_list, link) {
+		struct wl_pointer *pointer = seat->seat.pointer;
+		int32_t x, y;
+
+		if (!pointer)
+			continue;
+
+		x = wl_fixed_to_int(pointer->x);
+		y = wl_fixed_to_int(pointer->y);
+
+		if (!pixman_region32_contains_point(&old_output_region,
+						    x, y, NULL) ||
+		    pixman_region32_contains_point(&output->region,
+						   x, y, NULL))
+			continue;
+
+		if (x >= output->x + output->width)
+			x = output->x + output->width - 1;
+		if (y >= output->y + output->height)
+			y = output->y + output->height - 1;
+
+		pointer->x = wl_fixed_from_int(x);
+		pointer->y = wl_fixed_from_int(y);
+	}
+
+	pixman_region32_fini(&old_output_region);
+
 	return ret;
 }