[PATCH wayland] data_device: use a regular surface for drag icons

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Fri Feb 10 08:31:34 PST 2012


Change the data_device.attach request to data_device.set_surface. This
request will create a surface that will follow the mouse cursor. Client
provide the surface contests with the regular surface_attach.

Since data_device is implemented in libwayland-server, add a server
hook for the compositor to set the drag icon surface. An alternate
surface implementation in libwayland-server is then used to multiplex
the requests of different clients to the single surface on the
compositor side.
---
 protocol/wayland.xml |   18 +++++--
 src/data-device.c    |  142 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/wayland-server.h |    5 ++
 3 files changed, 152 insertions(+), 13 deletions(-)

diff --git a/protocol/wayland.xml b/protocol/wayland.xml
index c445d3f..081b0f6 100644
--- a/protocol/wayland.xml
+++ b/protocol/wayland.xml
@@ -282,11 +282,19 @@
       <arg name="time" type="uint"/>
     </request>
 
-    <request name="attach">
-      <arg name="time" type="uint"/>
-      <arg name="buffer" type="object" interface="wl_buffer"/>
-      <arg name="x" type="int"/>
-      <arg name="y" type="int"/>
+    <request name="set_surface">
+      <description summary="create a surface that follows the cursor">
+	Create a surface that will follow the cursor during a drag.
+	The distance between the top-left corner of this surface and
+	the cursor's hotspot is maintained on mouse movement. Initially
+	this distance is set by parameters x and y.
+
+	This surface should be destroyed with surface.destroy.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_surface" />
+      <arg name="x" type="int" />
+      <arg name="y" type="int" />
     </request>
 
     <request name="set_selection">
diff --git a/src/data-device.c b/src/data-device.c
index 95b1a9d..1248267 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -232,6 +232,9 @@ drag_grab_button(struct wl_grab *grab,
 {
 	struct wl_input_device *device =
 		container_of(grab, struct wl_input_device, drag_grab);
+	struct wl_resource *surface_resource;
+	struct wl_surface_interface *interface;
+	struct wl_client *client;
 
 	if (device->drag_focus_resource &&
 	    device->grab_button == button && state == 0)
@@ -239,8 +242,15 @@ drag_grab_button(struct wl_grab *grab,
 				       WL_DATA_DEVICE_DROP);
 
 	if (device->button_count == 0 && state == 0) {
+		client = device->drag_data_source->resource.client;
+
 		wl_input_device_end_grab(device, time);
 		device->drag_data_source = NULL;
+
+		surface_resource = &device->drag_surface->resource;
+		interface = (struct wl_surface_interface *)
+			surface_resource->object.implementation;
+		interface->attach(client, surface_resource, NULL, 0, 0);
 	}
 }
 
@@ -269,13 +279,6 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
 }
 
 static void
-data_device_attach(struct wl_client *client, struct wl_resource *resource,
-		   uint32_t time,
-		   struct wl_resource *buffer, int32_t x, int32_t y)
-{
-}
-
-static void
 destroy_selection_data_source(struct wl_listener *listener,
 			      struct wl_resource *resource, uint32_t time)
 {
@@ -333,6 +336,45 @@ wl_input_device_set_selection(struct wl_input_device *device,
 		       &device->selection_data_source_listener.link);
 }
 
+static const struct wl_surface_interface drag_surface_interface;
+
+struct data_device_drag_surface {
+	struct wl_surface surface;
+	struct wl_resource resource;
+	struct wl_input_device *device;
+};
+
+static void
+data_device_set_surface(struct wl_client *client,
+			struct wl_resource *resource,
+			uint32_t id, int32_t x, int32_t y)
+{
+	struct wl_input_device *device = resource->data;
+	struct data_device_drag_surface *surface;
+
+	surface = malloc(sizeof *surface);
+	if (!surface) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	surface->resource.object.id = id;
+	surface->resource.object.interface = &wl_surface_interface;
+	surface->resource.object.implementation = (void (**)(void))
+		&drag_surface_interface;
+
+	surface->resource.data = surface;
+	surface->resource.client = client;
+	surface->resource.destroy = NULL;
+
+	surface->device = device;
+
+	device->drag_icon_x = x;
+	device->drag_icon_y = y;
+
+	wl_client_add_resource(client, &surface->resource);
+}
+
 static void
 data_device_set_selection(struct wl_client *client,
 			  struct wl_resource *resource,
@@ -347,11 +389,88 @@ data_device_set_selection(struct wl_client *client,
 
 static const struct wl_data_device_interface data_device_interface = {
 	data_device_start_drag,
-	data_device_attach,
+	data_device_set_surface,
 	data_device_set_selection,
 };
 
 static void
+drag_surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	struct data_device_drag_surface *surface = resource->data;
+
+	wl_resource_destroy(resource, 0);
+	free(surface);
+}
+
+static void
+drag_surface_attach(struct wl_client *client,
+	       struct wl_resource *resource,
+	       struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
+{
+	struct data_device_drag_surface *surface = resource->data;
+	struct wl_input_device *device = surface->device;
+	struct wl_resource *drag_surface_resource;
+	struct wl_surface_interface *surface_interface;
+
+	if (!device->drag_surface || !device->drag_data_source)
+		return;
+
+	drag_surface_resource = &device->drag_surface->resource;
+	surface_interface = (struct wl_surface_interface *)
+		drag_surface_resource->object.implementation;
+
+	surface_interface->attach(client, drag_surface_resource,
+				  buffer_resource, sx, sy);
+}
+
+static void
+drag_surface_damage(struct wl_client *client,
+	       struct wl_resource *resource,
+	       int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	struct data_device_drag_surface *surface = resource->data;
+	struct wl_input_device *device = surface->device;
+	struct wl_resource *drag_surface_resource;
+	struct wl_surface_interface *surface_interface;
+
+	if (!device->drag_surface || !device->drag_data_source)
+		return;
+
+	drag_surface_resource = &device->drag_surface->resource;
+	surface_interface = (struct wl_surface_interface *)
+		drag_surface_resource->object.implementation;
+
+	surface_interface->damage(client, drag_surface_resource,
+				  x, y, width, height);
+}
+
+static void
+drag_surface_frame(struct wl_client *client,
+	      struct wl_resource *resource, uint32_t callback)
+{
+	struct data_device_drag_surface *surface = resource->data;
+	struct wl_input_device *device = surface->device;
+	struct wl_resource *drag_surface_resource;
+	struct wl_surface_interface *surface_interface;
+
+	if (!device->drag_surface || !device->drag_data_source)
+		return;
+
+	drag_surface_resource = &device->drag_surface->resource;
+	surface_interface = (struct wl_surface_interface *)
+		drag_surface_resource->object.implementation;
+
+	surface_interface->frame(client, drag_surface_resource, callback);
+}
+
+static const struct wl_surface_interface drag_surface_interface = {
+	drag_surface_destroy,
+	drag_surface_attach,
+	drag_surface_damage,
+	drag_surface_frame
+};
+
+static void
 destroy_data_source(struct wl_resource *resource)
 {
 	struct wl_data_source *source =
@@ -452,6 +571,13 @@ wl_data_device_set_keyboard_focus(struct wl_input_device *device)
 	}
 }
 
+WL_EXPORT void
+wl_data_device_set_drag_surface(struct wl_input_device *device,
+				struct wl_surface *surface)
+{
+	device->drag_surface = surface;
+}
+
 WL_EXPORT int
 wl_data_device_manager_init(struct wl_display *display)
 {
diff --git a/src/wayland-server.h b/src/wayland-server.h
index 53f918c..e965b2f 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -212,6 +212,8 @@ struct wl_input_device {
 	struct wl_resource *drag_focus_resource;
 	struct wl_listener drag_focus_listener;
 	struct wl_grab drag_grab;
+	struct wl_surface *drag_surface;
+	int32_t drag_icon_x, drag_icon_y;
 
 	struct wl_data_source *selection_data_source;
 	struct wl_listener selection_data_source_listener;
@@ -277,6 +279,9 @@ wl_input_device_set_keyboard_focus(struct wl_input_device *device,
 				   uint32_t time);
 void
 wl_data_device_set_keyboard_focus(struct wl_input_device *device);
+void
+wl_data_device_set_drag_surface(struct wl_input_device *device,
+				struct wl_surface *surface);
 int
 wl_data_device_manager_init(struct wl_display *display);
 
-- 
1.7.4.1



More information about the wayland-devel mailing list