[PATCH 4/4] Make the DND client actually work.

Joel Teichroeb joel at teichroeb.net
Tue Nov 30 10:22:16 PST 2010


The DND client now sends a "application/x-wayland-dnd-flower" instead of
"text/plain".
Made each flower keep its own seed. This may change in the future, but
this is a good starting point.
Added a simple reference counter for dnd_offer so that it will be freed
if the flower is dragged out of the window and not freed when dropped,
untill it is done with. This reference counter is not used everywhere
beucase there are only two places where the dnd_offer should be
destroyed.
Fixed a crash with using g_io_channel_read_chars by using read instead.
Used the new wl_drag_offer_reject to tell the client that their drag was
not wanted so they can reset the flower. Some animation from the
compositor could come in the future.
---
 clients/dnd.c |  154 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 122 insertions(+), 32 deletions(-)

diff --git a/clients/dnd.c b/clients/dnd.c
index dedf353..b902a67 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -53,6 +53,9 @@ struct dnd_drag {
 	struct dnd *dnd;
 	struct input *input;
 	uint32_t time;
+	struct item *item;
+	int x_offset, y_offset;
+	const char *mime_type;
 };
 
 struct dnd_offer {
@@ -60,20 +63,43 @@ struct dnd_offer {
 	struct wl_array types;
 	const char *drag_type;
 	uint32_t tag;
+	int x, y;
+	
+	/* Reference counting to see if the dnd_offer should be freed
+	 * when the surface is null. */
+	int refs;
 };
 
 struct item {
 	cairo_surface_t *surface;
+	int seed;
 	int x, y;
 };
 
+struct dnd_flower_message {
+	int seed, x_offset, y_offset;
+};
+
+
 static const int item_width = 64;
 static const int item_height = 64;
 static const int item_padding = 16;
 
 static struct item *
-item_create(struct display *display, int x, int y)
+item_create(struct display *display, int x, int y, int seed)
 {
+	struct item *item;
+	struct timeval tv;
+
+	item = malloc(sizeof *item);
+	if (item == NULL)
+		return NULL;
+	
+	
+	gettimeofday(&tv, NULL);
+	item->seed = seed ? seed : tv.tv_usec;
+	srandom(item->seed);
+	
 	const int petal_count = 3 + random() % 5;
 	const double r1 = 20 + random() % 10;
 	const double r2 = 5 + random() % 12;
@@ -85,11 +111,7 @@ item_create(struct display *display, int x, int y)
 	double t, dt = 2 * M_PI / (petal_count * 2);
 	double x1, y1, x2, y2, x3, y3;
 	struct rectangle rect;
-	struct item *item;
 
-	item = malloc(sizeof *item);
-	if (item == NULL)
-		return NULL;
 
 	rect.width = item_width;
 	rect.height = item_height;
@@ -206,6 +228,31 @@ keyboard_focus_handler(struct window *window,
 	window_schedule_redraw(dnd->window);
 }
 
+static void 
+dnd_offer_destroy(struct dnd_offer *dnd_offer)
+{
+	if (dnd_offer->refs <= 0) {
+		wl_array_release(&dnd_offer->types);
+		free(dnd_offer);
+	} else {
+		--dnd_offer->refs;
+	}
+}
+
+static int
+dnd_add_item(struct dnd *dnd, struct item *item)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+		if (dnd->items[i] == 0) {
+			dnd->items[i] = item;
+			return i;
+		}
+	}
+	return -1;
+}
+
 static struct item *
 dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
 {
@@ -241,6 +288,7 @@ drag_target(void *data,
 
 	fprintf(stderr, "target %s\n", mime_type);
 	device = input_get_input_device(dnd_drag->input);
+	dnd_drag->mime_type = mime_type;
 	if (mime_type)
 		surface = dnd_drag->opaque;
 	else
@@ -255,17 +303,35 @@ static void
 drag_finish(void *data, struct wl_drag *drag, int fd)
 {
 	struct dnd_drag *dnd_drag = data;
-	char text[] = "[drop data]";
 
-	fprintf(stderr, "got 'finish', fd %d, sending message\n", fd);
+	if (!dnd_drag->mime_type) {
+		dnd_add_item(dnd_drag->dnd, dnd_drag->item);
+		window_schedule_redraw(dnd_drag->dnd->window);
+		return;
+	}
+	
+	struct dnd_flower_message dnd_flower_message;	
+	
+	
+	dnd_flower_message.seed = dnd_drag->item->seed;
+
+	dnd_flower_message.x_offset = dnd_drag->x_offset;
+	dnd_flower_message.y_offset = dnd_drag->y_offset;
+
+	fprintf(stderr, "got 'finish', fd %d, sending dnd_flower_message\n", fd);
 
-	write(fd, text, sizeof text);
+	write(fd, &dnd_flower_message, sizeof dnd_flower_message);
 	close(fd);
 
 	/* The 'finish' event marks the end of the session on the drag
 	 * source side and we need to clean up the drag object created
 	 * and the local state. */
 	wl_drag_destroy(drag);
+	
+	/* Destroy the item that has been dragged out */
+	cairo_surface_destroy(dnd_drag->item->surface);
+	free(dnd_drag->item);
+	
 	cairo_surface_destroy(dnd_drag->translucent);
 	cairo_surface_destroy(dnd_drag->opaque);
 	free(dnd_drag);
@@ -305,9 +371,8 @@ drag_offer_pointer_focus(void *data,
 	 * allocated. */
 	if (!surface) {
 		fprintf(stderr, "pointer focus NULL, session over\n");
-		wl_array_release(&dnd_offer->types);
-		free(dnd_offer);
 		wl_drag_offer_destroy(offer);
+		dnd_offer_destroy(dnd_offer);
 		return;
 	}
 
@@ -321,8 +386,8 @@ drag_offer_pointer_focus(void *data,
 	dnd_offer->dnd = window_get_user_data(window);
 
 	if (!dnd_get_item(dnd_offer->dnd, surface_x, surface_y)) {
-		wl_drag_offer_accept(offer, time, "text/plain");
-		dnd_offer->drag_type = "text/plain";
+		wl_drag_offer_accept(offer, time, "application/x-wayland-dnd-flower");
+		dnd_offer->drag_type = "application/x-wayland-dnd-flower";
 	} else {
 		wl_drag_offer_accept(offer, time, NULL);
 		dnd_offer->drag_type = NULL;
@@ -335,13 +400,14 @@ drag_offer_motion(void *data,
 		  int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
 {
 	struct dnd_offer *dnd_offer = data;
-	struct dnd *dnd = dnd_offer->dnd;
 
-	if (!dnd_get_item(dnd, surface_x, surface_y)) {
+	if (!dnd_get_item(dnd_offer->dnd, surface_x, surface_y)) {
 		fprintf(stderr, "drag offer motion %d, %d, accepting\n",
 			surface_x, surface_y);
-		wl_drag_offer_accept(offer, time, "text/plain");
-		dnd_offer->drag_type = "text/plain";
+		wl_drag_offer_accept(offer, time, "application/x-wayland-dnd-flower");
+		dnd_offer->drag_type = "application/x-wayland-dnd-flower";
+		dnd_offer->x = surface_x;
+		dnd_offer->y = surface_y;
 	} else {
 		fprintf(stderr, "drag offer motion %d, %d, declining\n",
 			surface_x, surface_y);
@@ -354,19 +420,31 @@ static gboolean
 drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
 {
 	struct dnd_offer *dnd_offer = data;
-	char buffer[256];
+	struct dnd *dnd = dnd_offer->dnd;
+	struct dnd_flower_message dnd_flower_message;
 	int fd;
 	unsigned int len;
-	GError *err = NULL;
 
-	g_io_channel_read_chars(source, buffer, sizeof buffer, &len, &err);
-	fprintf(stderr, "read %d bytes: %s\n", len, buffer);
 	fd = g_io_channel_unix_get_fd(source);
+	len = read(fd, &dnd_flower_message, sizeof dnd_flower_message);
+	fprintf(stderr, "read %d bytes\n", len);
+	
 	close(fd);
 	g_source_remove(dnd_offer->tag);
 
 	g_io_channel_unref(source);
-
+	
+	
+	struct item *item = item_create(dnd->display, 
+		dnd_offer->x-dnd_flower_message.x_offset-26, 
+		dnd_offer->y-dnd_flower_message.y_offset-66, 
+		dnd_flower_message.seed);
+
+	dnd_add_item(dnd, item);
+	window_schedule_redraw(dnd->window);
+	
+	dnd_offer_destroy(dnd_offer);
+	
 	return TRUE;
 }
 
@@ -379,15 +457,14 @@ drag_offer_drop(void *data, struct wl_drag_offer *offer)
 
 	if (!dnd_offer->drag_type) {
 		fprintf(stderr, "got 'drop', but no target\n");
-		/* FIXME: Should send response so compositor and
-		 * source knows it's over. Can't send -1 to indicate
-		 * 'no target' though becauses of the way fd passing
-		 * currently works.  */
+		wl_drag_offer_reject(offer);
 		return;
 	}
 
 	fprintf(stderr, "got 'drop', sending write end of pipe\n");
 
+	++dnd_offer->refs;
+
 	pipe(p);
 	wl_drag_offer_receive(offer, p[1]);
 	close(p[1]);
@@ -412,6 +489,8 @@ drag_offer_handler(struct wl_drag_offer *offer, struct display *display)
 	dnd_offer = malloc(sizeof *dnd_offer);
 	if (dnd_offer == NULL)
 		return;
+	
+	dnd_offer->refs = 0;
 
 	wl_drag_offer_add_listener(offer, &drag_offer_listener, dnd_offer);
 	wl_array_init(&dnd_offer->types);
@@ -477,6 +556,7 @@ dnd_button_handler(struct window *window,
 	struct item *item;
 	struct rectangle rectangle;
 	struct dnd_drag *dnd_drag;
+	int i;
 
 	window_get_child_rectangle(dnd->window, &rectangle);
 	input_get_position(input, &x, &y);
@@ -491,14 +571,28 @@ dnd_button_handler(struct window *window,
 		dnd_drag->dnd = dnd;
 		dnd_drag->input = input;
 		dnd_drag->time = time;
+		dnd_drag->item = item;
+		dnd_drag->x_offset = x - item->x;
+		dnd_drag->y_offset = y - item->y;
+		
+		for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+			if (item == dnd->items[i]){
+				dnd->items[i] = 0;
+				break;
+			}
+		}
 
 		dnd_drag->opaque =
 			create_drag_cursor(dnd_drag, item, x, y, 1);
 		dnd_drag->translucent =
 			create_drag_cursor(dnd_drag, item, x, y, 0.2);
 
-		window_start_drag(window, input, time,
-				  &drag_listener, dnd_drag);
+		struct wl_drag *wl_drag = 
+			window_start_drag(window, input, time,
+					  &drag_listener, dnd_drag);
+		
+		wl_drag_offer(wl_drag, "application/x-wayland-dnd-flower");
+		window_schedule_redraw(dnd->window);
 	}
 }
 
@@ -542,7 +636,7 @@ dnd_create(struct display *display)
 		x = (i % 4) * (item_width + item_padding) + item_padding;
 		y = (i / 4) * (item_height + item_padding) + item_padding;
 		if ((i ^ (i >> 2)) & 1)
-			dnd->items[i] = item_create(display, x, y);
+			dnd->items[i] = item_create(display, x, y, 0);
 		else
 			dnd->items[i] = NULL;
 	}
@@ -575,10 +669,6 @@ main(int argc, char *argv[])
 {
 	struct display *d;
 	struct dnd *dnd;
-	struct timeval tv;
-
-	gettimeofday(&tv, NULL);
-	srandom(tv.tv_usec);
 
 	d = display_create(&argc, &argv, option_entries);
 	if (d == NULL) {
-- 
1.7.3.2



More information about the wayland-devel mailing list