diff --git a/src/compositor.c b/src/compositor.c
index a505f88..d6acf89 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -198,6 +198,8 @@ weston_surface_create(struct weston_compositor *compositor)
 	surface->output = NULL;
 
 	pixman_region32_init(&surface->damage);
+	pixman_region32_init(&surface->opaque);
+	pixman_region32_init(&surface->input);
 	pixman_region32_init(&surface->transform.opaque);
 	wl_list_init(&surface->frame_callback_list);
 
@@ -315,6 +317,10 @@ weston_surface_update_transform_disable(struct weston_surface *surface)
 				  surface->geometry.y,
 				  surface->geometry.width,
 				  surface->geometry.height);
+	pixman_region32_init(&surface->transform.opaque);
+	pixman_region32_copy(&surface->transform.opaque, &surface->opaque);
+	pixman_region32_translate(&surface->transform.opaque,
+				  surface->geometry.x, surface->geometry.y);
 }
 
 static int
@@ -344,6 +350,8 @@ weston_surface_update_transform_enable(struct weston_surface *surface)
 	surface_compute_bbox(surface, 0, 0, surface->geometry.width,
 			     surface->geometry.height,
 			     &surface->transform.boundingbox);
+	pixman_region32_init(&surface->transform.opaque);
+
 	return 0;
 }
 
@@ -518,11 +526,9 @@ weston_compositor_pick_surface(struct weston_compositor *compositor,
 	struct weston_surface *surface;
 
 	wl_list_for_each(surface, &compositor->surface_list, link) {
-		if (!surface->pickable)
-			continue;
 		weston_surface_from_global(surface, x, y, sx, sy);
-		if (0 <= *sx && *sx < surface->geometry.width &&
-		    0 <= *sy && *sy < surface->geometry.height)
+		if (pixman_region32_contains_point(&surface->input,
+						   *sx, *sy, NULL))
 			return surface;
 	}
 
@@ -604,7 +610,8 @@ destroy_surface(struct wl_resource *resource)
 
 	pixman_region32_fini(&surface->transform.boundingbox);
 	pixman_region32_fini(&surface->damage);
-	pixman_region32_fini(&surface->transform.opaque);
+	pixman_region32_fini(&surface->opaque);
+	pixman_region32_fini(&surface->input);
 
 	free(surface);
 }
@@ -1207,11 +1214,37 @@ surface_frame(struct wl_client *client,
 	}
 }
 
+static void
+surface_set_opaque_region(struct wl_client *client,
+			  struct wl_resource *resource,
+			  struct wl_resource *region_resource)
+{
+	struct weston_surface *surface = resource->data;
+	struct weston_region *region = region_resource->data;
+
+	pixman_region32_copy(&surface->opaque, &region->region);
+	surface->geometry.dirty = 1;
+}
+
+static void
+surface_set_input_region(struct wl_client *client,
+			 struct wl_resource *resource,
+			 struct wl_resource *region_resource)
+{
+	struct weston_surface *surface = resource->data;
+	struct weston_region *region = region_resource->data;
+
+	pixman_region32_copy(&surface->input, &region->region);
+
+}
+
 const static struct wl_surface_interface surface_interface = {
 	surface_destroy,
 	surface_attach,
 	surface_damage,
-	surface_frame
+	surface_frame,
+	surface_set_opaque_region,
+	surface_set_input_region
 };
 
 static void
@@ -1235,13 +1268,81 @@ compositor_create_surface(struct wl_client *client,
 		(void (**)(void)) &surface_interface;
 	surface->surface.resource.data = surface;
 
-	surface->pickable = 1;
-
 	wl_client_add_resource(client, &surface->surface.resource);
 }
 
+static void
+destroy_region(struct wl_resource *resource)
+{
+	struct weston_region *region =
+		container_of(resource, struct weston_region, resource);
+
+	pixman_region32_fini(&region->region);
+	free(region);
+}
+
+static void
+region_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource, weston_compositor_get_time());
+}
+
+static void
+region_add(struct wl_client *client, struct wl_resource *resource,
+	   int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	struct weston_region *region = resource->data;
+
+	pixman_region32_union_rect(&region->region, &region->region,
+				   x, y, width, height);
+}
+
+static void
+region_subtract(struct wl_client *client, struct wl_resource *resource,
+		int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	struct weston_region *region = resource->data;
+	pixman_region32_t rect;
+
+	pixman_region32_init_rect(&rect, x, y, width, height);
+	pixman_region32_subtract(&region->region, &region->region, &rect);
+	pixman_region32_fini(&rect);
+}
+
+static const struct wl_region_interface region_interface = {
+	region_destroy,
+	region_add,
+	region_subtract
+};
+
+static void
+compositor_create_region(struct wl_client *client,
+			 struct wl_resource *resource, uint32_t id)
+{
+	struct weston_region *region;
+
+	region = malloc(sizeof *region);
+	if (region == NULL) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	region->resource.destroy = destroy_region;
+
+	region->resource.object.id = id;
+	region->resource.object.interface = &wl_region_interface;
+	region->resource.object.implementation =
+		(void (**)(void)) &region_interface;
+	region->resource.data = region;
+
+	pixman_region32_init(&region->region);
+
+	wl_client_add_resource(client, &region->resource);
+}
+
 const static struct wl_compositor_interface compositor_interface = {
 	compositor_create_surface,
+	compositor_create_region
 };
 
 WL_EXPORT void
@@ -1781,7 +1882,6 @@ weston_input_update_drag_surface(struct wl_input_device *input_device,
 		surface_changed = 1;
 
 	if (!input_device->drag_surface || surface_changed) {
-		device->drag_surface->pickable = 1;
 		device->drag_surface = NULL;
 		if (!surface_changed)
 			return;
@@ -1790,7 +1890,6 @@ weston_input_update_drag_surface(struct wl_input_device *input_device,
 	if (!device->drag_surface || surface_changed) {
 		device->drag_surface = (struct weston_surface *)
 			input_device->drag_surface;
-		device->drag_surface->pickable = 0;
 
 		weston_surface_set_position(device->drag_surface,
 					    input_device->x, input_device->y);
diff --git a/src/compositor.h b/src/compositor.h
index efd71e9..983b9ff 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -208,6 +208,11 @@ enum weston_output_flags {
 	WL_OUTPUT_FLIPPED = 0x01
 };
 
+struct weston_region {
+	struct wl_resource resource;
+	pixman_region32_t region;
+};
+
 /* Using weston_surface transformations
  *
  * To add a transformation to a surface, create a struct weston_transform, and
@@ -238,6 +243,8 @@ struct weston_surface {
 	struct weston_compositor *compositor;
 	GLuint texture;
 	pixman_region32_t damage;
+	pixman_region32_t opaque;
+	pixman_region32_t input;
 	int32_t pitch;
 	struct wl_list link;
 	struct wl_list buffer_link;
@@ -245,7 +252,6 @@ struct weston_surface {
 	GLfloat color[4];
 	uint32_t alpha;
 	int overlapped;
-	int pickable;
 
 	/* Surface geometry state, mutable.
 	 * If you change anything, set dirty = 1.
