Use new grab api
diff --git a/src/compositor.c b/src/compositor.c
index 2627987..8e24f8f 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -307,6 +307,14 @@
 		pixman_region32_init(&surface->opaque);
 }
 
+static void
+weston_surface_transform(struct weston_surface *surface,
+		       int32_t x, int32_t y, int32_t *sx, int32_t *sy)
+{
+	*sx = x - surface->x;
+	*sy = y - surface->y;
+}
+
 WL_EXPORT uint32_t
 weston_compositor_get_time(void)
 {
@@ -318,28 +326,42 @@
 }
 
 WL_EXPORT void
+weston_device_repick(struct wl_input_device *device, uint32_t time)
+{
+	struct weston_input_device *wd = (struct weston_input_device *) device;
+	const struct wl_grab_interface *interface;
+	struct weston_surface *surface, *focus;
+
+	surface = weston_compositor_pick_surface(wd->compositor,
+						 device->x, device->y,
+						 &device->current_x,
+						 &device->current_y);
+
+	if (&surface->surface != device->current) {
+		interface = device->grab->interface;
+		interface->focus(device->grab, time, &surface->surface,
+				 device->current_x, device->current_y);
+		device->current = &surface->surface;
+	}
+
+	focus = (struct weston_surface *) device->grab->focus;
+	if (focus)
+		weston_surface_transform(focus, device->x, device->y,
+					 &device->grab->x, &device->grab->y);
+}
+
+WL_EXPORT void
 weston_compositor_repick(struct weston_compositor *compositor)
 {
 	struct weston_input_device *device;
-	struct weston_surface *surface;
-	int32_t sx, sy;
 	uint32_t time;
 
 	if (!compositor->focus)
 		return;
 
 	time = weston_compositor_get_time();
-	wl_list_for_each(device, &compositor->input_device_list, link) {
-		if (device->input_device.grab)
-			continue;
-		surface = pick_surface(&device->input_device, &sx, &sy);
-		wl_input_device_set_pointer_focus(&device->input_device,
-						  &surface->surface,
-						  time,
-						  device->input_device.x,
-						  device->input_device.y,
-						  sx, sy);
-	}
+	wl_list_for_each(device, &compositor->input_device_list, link)
+		weston_device_repick(&device->input_device, time);
 }
 
 static void
@@ -1071,15 +1093,7 @@
 	compositor_create_surface,
 };
 
-static void
-weston_surface_transform(struct weston_surface *surface,
-		       int32_t x, int32_t y, int32_t *sx, int32_t *sy)
-{
-	*sx = x - surface->x;
-	*sy = y - surface->y;
-}
-
-static struct weston_surface *
+WL_EXPORT struct weston_surface *
 weston_compositor_pick_surface(struct weston_compositor *compositor,
 			       int32_t x, int32_t y, int32_t *sx, int32_t *sy)
 {
@@ -1097,56 +1111,56 @@
 	return NULL;
 }
 
-WL_EXPORT struct weston_surface *
-pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy)
+static void
+default_grab_focus(struct wl_grab *grab, uint32_t time,
+		   struct wl_surface *surface, int32_t x, int32_t y)
 {
-	struct weston_input_device *wd = (struct weston_input_device *) device;
+	struct wl_input_device *device = grab->input_device;
 
-	return weston_compositor_pick_surface(wd->compositor,
-					    device->x, device->y, sx, sy);
+	if (device->button_count > 0)
+		return;
+
+	wl_input_device_set_pointer_focus(device, surface, time,
+					  device->x, device->y, x, y);
 }
 
-
 static void
-implicit_grab_motion(struct wl_grab *grab,
-		     uint32_t time, int32_t x, int32_t y)
+default_grab_motion(struct wl_grab *grab,
+		    uint32_t time, int32_t x, int32_t y)
 {
-	struct weston_input_device *device =
-		(struct weston_input_device *) grab->input_device;
-	struct weston_surface *es =
-		(struct weston_surface *) device->input_device.pointer_focus;
-	int32_t sx, sy;
+	struct wl_input_device *device = grab->input_device;
 	struct wl_resource *resource;
 
 	resource = grab->input_device->pointer_focus_resource;
-	if (resource) {
-		weston_surface_transform(es, x, y, &sx, &sy);
+	if (resource)
 		wl_resource_post_event(resource, WL_INPUT_DEVICE_MOTION,
-				       time, x, y, sx, sy);
-	}
+				       time, device->x, device->y, x, y);
 }
 
 static void
-implicit_grab_button(struct wl_grab *grab,
-		     uint32_t time, int32_t button, int32_t state)
+default_grab_button(struct wl_grab *grab,
+		    uint32_t time, int32_t button, int32_t state)
 {
+	struct wl_input_device *device = grab->input_device;
 	struct wl_resource *resource;
 
-	resource = grab->input_device->pointer_focus_resource;
+	if (device->button_count == 0 && state == 0)
+		wl_input_device_set_pointer_focus(device,
+						  device->current, time,
+						  device->x, device->y,
+						  device->current_x,
+						  device->current_y);
+
+	resource = device->pointer_focus_resource;
 	if (resource)
 		wl_resource_post_event(resource, WL_INPUT_DEVICE_BUTTON,
 				       time, button, state);
 }
 
-static void
-implicit_grab_end(struct wl_grab *grab, uint32_t time)
-{
-}
-
-static const struct wl_grab_interface implicit_grab_interface = {
-	implicit_grab_motion,
-	implicit_grab_button,
-	implicit_grab_end
+static const struct wl_grab_interface default_grab_interface = {
+	default_grab_focus,
+	default_grab_motion,
+	default_grab_button
 };
 
 WL_EXPORT void
@@ -1199,12 +1213,10 @@
 WL_EXPORT void
 notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
 {
-	struct weston_surface *es;
 	struct weston_output *output;
 	const struct wl_grab_interface *interface;
 	struct weston_input_device *wd = (struct weston_input_device *) device;
 	struct weston_compositor *ec = wd->compositor;
-	int32_t sx, sy;
 	int x_valid = 0, y_valid = 0;
 	int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
 
@@ -1245,19 +1257,10 @@
 	device->x = x;
 	device->y = y;
 
-	if (device->grab) {
-		interface = device->grab->interface;
-		interface->motion(device->grab, time, x, y);
-	} else {
-		es = pick_surface(device, &sx, &sy);
-		wl_input_device_set_pointer_focus(device,
-						  &es->surface,
-						  time, x, y, sx, sy);
-		if (device->pointer_focus_resource)
-			wl_resource_post_event(device->pointer_focus_resource,
-					       WL_INPUT_DEVICE_MOTION,
-					       time, x, y, sx, sy);
-	}
+	weston_device_repick(device, time);
+	interface = device->grab->interface;
+	interface->motion(device->grab, time,
+			  device->grab->x, device->grab->y);
 
 	if (wd->sprite) {
 		weston_surface_damage_below(wd->sprite);
@@ -1285,34 +1288,25 @@
 {
 	struct weston_input_device *wd = (struct weston_input_device *) device;
 	struct weston_compositor *compositor = wd->compositor;
-	struct weston_surface *surface =
-		(struct weston_surface *) device->pointer_focus;
-	int32_t sx, sy;
 
-	if (state)
+	if (state) {
 		weston_compositor_idle_inhibit(compositor);
-	else
+		if (device->button_count == 0) {
+			device->grab_button = button;
+			device->grab_time = time;
+			device->grab_x = device->x;
+			device->grab_y = device->y;
+		}
+		device->button_count++;
+	} else {
 		weston_compositor_idle_release(compositor);
+		device->button_count--;
+	}
 
 	weston_compositor_run_binding(compositor, wd, time, 0, button, state);
 
-	if (state && surface && device->grab == NULL) {
-		wl_input_device_start_grab(device,
-					   &device->implicit_grab,
-					   button, time);
-	}
+	device->grab->interface->button(device->grab, time, button, state);
 
-	if (device->grab)
-		device->grab->interface->button(device->grab, time,
-						button, state);
-
-	if (!state && device->grab && device->grab_button == button) {
-		wl_input_device_end_grab(device, time);
-		surface = pick_surface(device, &sx, &sy);
-		wl_input_device_set_pointer_focus(device, &surface->surface,
-						  time, device->x, device->y,
-						  sx, sy);
-	}
 }
 
 static void
@@ -1387,22 +1381,15 @@
 {
 	struct weston_input_device *wd = (struct weston_input_device *) device;
 	struct weston_compositor *compositor = wd->compositor;
-	struct weston_surface *es;
-	int32_t sx, sy;
 
 	if (output) {
 		device->x = x;
 		device->y = y;
-		es = pick_surface(device, &sx, &sy);
-		wl_input_device_set_pointer_focus(device,
-						  &es->surface,
-						  time, x, y, sx, sy);
-
 		compositor->focus = 1;
+		weston_compositor_repick(compositor);
 	} else {
-		wl_input_device_set_pointer_focus(device, NULL,
-						  time, 0, 0, 0, 0);
 		compositor->focus = 0;
+		weston_compositor_repick(compositor);
 	}
 }
 
@@ -1678,7 +1665,9 @@
 	device->modifier_state = 0;
 	device->num_tp = 0;
 
-	device->input_device.implicit_grab.interface = &implicit_grab_interface;
+	device->input_device.default_grab.interface = &default_grab_interface;
+	device->input_device.default_grab.input_device = &device->input_device;
+	device->input_device.grab = &device->input_device.default_grab;
 
 	wl_list_insert(ec->input_device_list.prev, &device->link);
 
diff --git a/src/compositor.h b/src/compositor.h
index f6c87da..bf21fee 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -115,10 +115,10 @@
 	struct wl_surface *drag_focus;
 	struct wl_resource *drag_focus_resource;
 	struct wl_listener drag_focus_listener;
+	struct wl_grab drag_grab;
 
 	struct weston_data_source *selection_data_source;
 	struct wl_listener selection_data_source_listener;
-	struct wl_grab grab;
 	struct wl_list selection_listener_list;
 
 	uint32_t num_tp;
@@ -297,6 +297,8 @@
 weston_input_device_set_selection(struct weston_input_device *device,
 				  struct weston_data_source *source,
 				  uint32_t time);
+void
+weston_device_repick(struct wl_input_device *device, uint32_t time);
 
 void
 weston_spring_init(struct weston_spring *spring,
@@ -339,6 +341,9 @@
 weston_output_finish_frame(struct weston_output *output, int msecs);
 void
 weston_output_damage(struct weston_output *output);
+struct weston_surface *
+weston_compositor_pick_surface(struct weston_compositor *compositor,
+			       int32_t x, int32_t y, int32_t *sx, int32_t *sy);
 void
 weston_compositor_repick(struct weston_compositor *compositor);
 void
@@ -397,9 +402,6 @@
 				int32_t x, int32_t y,
 				int32_t width, int32_t height);
 
-struct weston_surface *
-pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy);
-
 uint32_t
 weston_compositor_get_time(void);
 
diff --git a/src/data-device.c b/src/data-device.c
index 500c6b0..049dcb0 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -179,15 +179,13 @@
 }
 
 static void
-drag_set_focus(struct weston_input_device *device,
-	       struct wl_surface *surface, uint32_t time,
-	       int32_t x, int32_t y)
+drag_grab_focus(struct wl_grab *grab, uint32_t time,
+		struct wl_surface *surface, int32_t x, int32_t y)
 {
+	struct weston_input_device *device =
+		container_of(grab, struct weston_input_device, drag_grab);
 	struct wl_resource *resource, *offer;
 
-	if (device->drag_focus == surface)
-		return;
-
 	if (device->drag_focus_resource) {
 		wl_resource_post_event(device->drag_focus_resource,
 				       WL_DATA_DEVICE_LEAVE);
@@ -212,6 +210,7 @@
 		wl_list_insert(resource->destroy_listener_list.prev,
 			       &device->drag_focus_listener.link);
 		device->drag_focus_resource = resource;
+		grab->focus = surface;
 	}
 }
 
@@ -220,13 +219,9 @@
 		 uint32_t time, int32_t x, int32_t y)
 {
 	struct weston_input_device *device =
-		container_of(grab, struct weston_input_device, grab);
-	struct weston_surface *es;
+		container_of(grab, struct weston_input_device, drag_grab);
 
-	es = pick_surface(&device->input_device, &x, &y);
-	drag_set_focus(device, &es->surface, time, x, y);
-
-	if (es && device->drag_focus_resource)
+	if (device->drag_focus_resource)
 		wl_resource_post_event(device->drag_focus_resource,
 				       WL_DATA_DEVICE_MOTION, time, x, y);
 }
@@ -235,26 +230,24 @@
 drag_grab_button(struct wl_grab *grab,
 		 uint32_t time, int32_t button, int32_t state)
 {
-}
-
-static void
-drag_grab_end(struct wl_grab *grab, uint32_t time)
-{
 	struct weston_input_device *device =
-		container_of(grab, struct weston_input_device, grab);
+		container_of(grab, struct weston_input_device, drag_grab);
 
-	if (device->drag_focus_resource)
+	if (device->drag_focus_resource &&
+	    device->input_device.grab_button == button && state == 0)
 		wl_resource_post_event(device->drag_focus_resource,
 				       WL_DATA_DEVICE_DROP);
 
-	drag_set_focus(device, NULL, time, 0, 0);
-	device->drag_data_source = NULL;
+	if (device->input_device.button_count == 0 && state == 0) {
+		wl_input_device_end_grab(&device->input_device, time);
+		device->drag_data_source = NULL;
+	}
 }
 
 static const struct wl_grab_interface drag_grab_interface = {
+	drag_grab_focus,
 	drag_grab_motion,
 	drag_grab_button,
-	drag_grab_end
 };
 
 static void
@@ -263,26 +256,17 @@
 		       struct wl_resource *surface_resource, uint32_t time)
 {
 	struct weston_input_device *device = resource->data;
-	struct weston_surface *surface = surface_resource->data;
-	struct weston_surface *target;
-	int32_t sx, sy;
 
 	/* FIXME: Check that client has implicit grab on the surface
 	 * that matches the given time. */
 
 	/* FIXME: Check that the data source type array isn't empty. */
 
-	if (wl_input_device_update_grab(&device->input_device, &device->grab,
-					&surface->surface, time) < 0)
-		return;
-
-	device->grab.interface = &drag_grab_interface;
+	device->drag_grab.interface = &drag_grab_interface;
 	device->drag_data_source = source_resource->data;
 
-	target = pick_surface(&device->input_device, &sx, &sy);
-	wl_input_device_set_pointer_focus(&device->input_device,
-					  NULL, time, 0, 0, 0, 0);
-	drag_set_focus(device, &target->surface, time, sx, sy);
+	wl_input_device_start_grab(&device->input_device,
+				   &device->drag_grab, time);
 }
 
 static void
diff --git a/src/shell.c b/src/shell.c
index a39adb3..b27067d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -126,37 +126,47 @@
 }
 
 static void
+noop_grab_focus(struct wl_grab *grab, uint32_t time,
+		struct wl_surface *surface, int32_t x, int32_t y)
+{
+	grab->focus = NULL;
+}
+
+static void
 move_grab_motion(struct wl_grab *grab,
-		   uint32_t time, int32_t x, int32_t y)
+		 uint32_t time, int32_t x, int32_t y)
 {
 	struct weston_move_grab *move = (struct weston_move_grab *) grab;
+	struct wl_input_device *device = grab->input_device;
 	struct weston_surface *es = move->surface;
 
-	weston_surface_configure(es, x + move->dx, y + move->dy,
-			       es->width, es->height);
+	weston_surface_configure(es,
+				 device->x + move->dx,
+				 device->y + move->dy,
+				 es->width, es->height);
 }
 
 static void
 move_grab_button(struct wl_grab *grab,
 		 uint32_t time, int32_t button, int32_t state)
 {
-}
+	struct wl_input_device *device = grab->input_device;
 
-static void
-move_grab_end(struct wl_grab *grab, uint32_t time)
-{
-	free(grab);
+	if (device->button_count == 0 && state == 0) {
+		wl_input_device_end_grab(device, time);
+		free(grab);
+	}
 }
 
 static const struct wl_grab_interface move_grab_interface = {
+	noop_grab_focus,
 	move_grab_motion,
 	move_grab_button,
-	move_grab_end
 };
 
 static int
 weston_surface_move(struct weston_surface *es,
-		  struct weston_input_device *wd, uint32_t time)
+		    struct weston_input_device *wd, uint32_t time)
 {
 	struct weston_move_grab *move;
 
@@ -169,11 +179,7 @@
 	move->dy = es->y - wd->input_device.grab_y;
 	move->surface = es;
 
-	if (wl_input_device_update_grab(&wd->input_device,
-					&move->grab, &es->surface, time) < 0) {
-		free(move);
-		return 0;
-	}
+	wl_input_device_start_grab(&wd->input_device, &move->grab, time);
 
 	wl_input_device_set_pointer_focus(&wd->input_device,
 					  NULL, time, 0, 0, 0, 0);
@@ -188,6 +194,11 @@
 	struct weston_input_device *wd = input_resource->data;
 	struct shell_surface *shsurf = resource->data;
 
+	if (wd->input_device.button_count == 0 ||
+	    wd->input_device.grab_time != time ||
+	    wd->input_device.pointer_focus != &shsurf->surface->surface)
+		return;
+
 	if (weston_surface_move(shsurf->surface, wd, time) < 0)
 		wl_resource_post_no_memory(resource);
 }
@@ -208,17 +219,17 @@
 	int32_t width, height;
 
 	if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
-		width = device->grab_x - x + resize->width;
+		width = device->grab_x - device->x + resize->width;
 	} else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
-		width = x - device->grab_x + resize->width;
+		width = device->x - device->grab_x + resize->width;
 	} else {
 		width = resize->width;
 	}
 
 	if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
-		height = device->grab_y - y + resize->height;
+		height = device->grab_y - device->y + resize->height;
 	} else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
-		height = y - device->grab_y + resize->height;
+		height = device->y - device->grab_y + resize->height;
 	} else {
 		height = resize->height;
 	}
@@ -232,18 +243,18 @@
 resize_grab_button(struct wl_grab *grab,
 		   uint32_t time, int32_t button, int32_t state)
 {
-}
+	struct wl_input_device *device = grab->input_device;
 
-static void
-resize_grab_end(struct wl_grab *grab, uint32_t time)
-{
-	free(grab);
+	if (device->button_count == 0 && state == 0) {
+		wl_input_device_end_grab(device, time);
+		free(grab);
+	}
 }
 
 static const struct wl_grab_interface resize_grab_interface = {
+	noop_grab_focus,
 	resize_grab_motion,
 	resize_grab_button,
-	resize_grab_end
 };
 
 static int
@@ -272,9 +283,7 @@
 	    (edges & 3) == 3 || (edges & 12) == 12)
 		goto err_out;
 
-	if (wl_input_device_update_grab(&wd->input_device,
-					&resize->grab, &es->surface, time) < 0)
-		goto err_out;
+	wl_input_device_start_grab(&wd->input_device, &resize->grab, time);
 
 	wl_input_device_set_pointer_focus(&wd->input_device,
 					  NULL, time, 0, 0, 0, 0);
@@ -296,6 +305,11 @@
 
 	/* FIXME: Reject if fullscreen */
 
+	if (wd->input_device.button_count == 0 ||
+	    wd->input_device.grab_time != time ||
+	    wd->input_device.pointer_focus != &shsurf->surface->surface)
+		return;
+
 	if (weston_surface_resize(shsurf, wd, time, edges) < 0)
 		wl_resource_post_no_memory(resource);
 }
@@ -865,7 +879,7 @@
 	struct weston_surface *focus;
 
 	focus = (struct weston_surface *) device->pointer_focus;
-	if (state && focus && device->grab == NULL)
+	if (state && focus && device->grab == &device->default_grab)
 		activate(compositor->shell, focus, wd, time);
 }