[PATCH wayland 1/2] add a dnd actions mechanism

Giulio Camuffo giuliocamuffo at gmail.com
Wed Mar 13 02:59:32 PDT 2013


When creating a wl_data_source the client must now set certain supported
actions on the data: COPY, MOVE or LINK. The target client will choose one
of these (or IGNORE) after receiving the data and will notify the server
which one it is, with wl_data_source_notify_received(). The wl_data_source
will receive the wl_data_source_complete() event, with the accepted action,
which means it must complete any pending task and free itself.
If the wl_data_offer does not accept any mime type the drop event won't
be delivered, but wl_data_source_cancelled() will be sent instead.
---
 protocol/wayland.xml | 54 +++++++++++++++++++++++++++++++++++++++++++++++++---
 src/data-device.c    | 45 ++++++++++++++++++++++++++++++++++++++++---
 src/wayland-server.h |  4 ++++
 3 files changed, 97 insertions(+), 6 deletions(-)

diff --git a/protocol/wayland.xml b/protocol/wayland.xml
index 0ce68ef..ee2d83f 100644
--- a/protocol/wayland.xml
+++ b/protocol/wayland.xml
@@ -296,7 +296,7 @@
   </interface>
 
 
-  <interface name="wl_data_offer" version="1">
+  <interface name="wl_data_offer" version="2">
     <description summary="offer to transfer data">
       A wl_data_offer represents a piece of data offered for transfer
       by another client (the source client).  It is used by the
@@ -341,9 +341,36 @@
 
       <arg name="type" type="string"/>
     </event>
+
+    <!-- Version 2 additions -->
+
+    <event name="actions" since="2">
+      <description summary="notify the possible actions">
+	This event notifies the offer of the possible action the source
+	client supports. The target client must accept one of them, or else
+	the drop operation will be ignored.
+      </description>
+      <arg name="value" type="uint"/>
+    </event>
+
+    <enum name="dnd_action" since="2">
+      <entry name="ignore" value="0"/>
+      <entry name="copy" value="1"/>
+      <entry name="move" value="2"/>
+      <entry name="link" value="4"/>
+    </enum>
+
+    <request name="notify_received" since="2">
+      <description summary="notify that the data has been received">
+	The client must issue this request when it has received the data.
+	It must accept and send a valid action, which must be either one of
+	the actions sent by the source client or the IGNORE action.
+      </description>
+      <arg name="action" type="uint"/>
+    </request>
   </interface>
 
-  <interface name="wl_data_source" version="1">
+  <interface name="wl_data_source" version="2">
     <description summary="offer to transfer data">
       The wl_data_source object is the source side of a wl_data_offer.
       It is created by the source client in a data transfer and
@@ -387,11 +414,32 @@
 
     <event name="cancelled">
       <description summary="selection was cancelled">
-	This data source has been replaced by another data source.
+	This data source has been replaced by another data source or
+	the drop operation was not accepted by the target client.
 	The client should clean up and destroy this data source.
       </description>
     </event>
 
+    <!-- Version 2 additions -->
+
+    <request name="set_actions" since="2">
+      <description summary="the data has been dropped">
+	Sets the actions the client supports for this operation.
+	The target client will chose one of them and will notify
+	this wl_data_source.
+      </description>
+      <arg name="actions" type="uint"/>
+    </request>
+
+    <event name="complete" since="2">
+      <description summary="the data has been dropped">
+	This event notifies the source client that it should finish sending
+	the data and any other pending operation and then clean up. It carries
+	the action accepted by the target client.
+      </description>
+      <arg name="action" type="uint"/>
+    </event>
+
   </interface>
 
   <interface name="wl_data_device" version="1">
diff --git a/src/data-device.c b/src/data-device.c
index 4255c13..7156e96 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -55,6 +55,16 @@ data_offer_receive(struct wl_client *client, struct wl_resource *resource,
 }
 
 static void
+data_offer_notify_received(struct wl_client *client, struct wl_resource *resource,
+					uint32_t action)
+{
+	struct wl_data_offer *offer = resource->data;
+
+	if (offer->source)
+		offer->source->complete(offer->source, action);
+}
+
+static void
 data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
 {
 	wl_resource_destroy(resource);
@@ -64,6 +74,7 @@ static const struct wl_data_offer_interface data_offer_interface = {
 	data_offer_accept,
 	data_offer_receive,
 	data_offer_destroy,
+	data_offer_notify_received,
 };
 
 static void
@@ -117,6 +128,7 @@ wl_data_source_send_offer(struct wl_data_source *source,
 
 	wl_array_for_each(p, &source->mime_types)
 		wl_data_offer_send_offer(&offer->resource, *p);
+	wl_data_offer_send_actions(&offer->resource, source->possible_actions);
 
 	return &offer->resource;
 }
@@ -142,9 +154,19 @@ data_source_destroy(struct wl_client *client, struct wl_resource *resource)
 	wl_resource_destroy(resource);
 }
 
+static void
+data_source_set_actions(struct wl_client *client, struct wl_resource *resource,
+						uint32_t actions)
+{
+	struct wl_data_source *source = resource->data;
+
+	source->possible_actions = actions;
+}
+
 static struct wl_data_source_interface data_source_interface = {
 	data_source_offer,
-	data_source_destroy
+	data_source_destroy,
+	data_source_set_actions
 };
 
 static struct wl_resource *
@@ -253,8 +275,12 @@ drag_grab_button(struct wl_pointer_grab *grab,
 
 	if (seat->drag_focus_resource &&
 	    seat->pointer->grab_button == button &&
-	    state == WL_POINTER_BUTTON_STATE_RELEASED)
-		wl_data_device_send_drop(seat->drag_focus_resource);
+	    state == WL_POINTER_BUTTON_STATE_RELEASED) {
+		if (seat->drag_data_source->accepted)
+			wl_data_device_send_drop(seat->drag_focus_resource);
+		else
+			seat->drag_data_source->cancel(seat->drag_data_source);
+	}
 
 	if (seat->pointer->button_count == 0 &&
 	    state == WL_POINTER_BUTTON_STATE_RELEASED) {
@@ -431,6 +457,7 @@ client_source_accept(struct wl_data_source *source,
 		     uint32_t time, const char *mime_type)
 {
 	wl_data_source_send_target(&source->resource, mime_type);
+	source->accepted = mime_type != NULL;
 }
 
 static void
@@ -448,6 +475,15 @@ client_source_cancel(struct wl_data_source *source)
 }
 
 static void
+client_source_complete(struct wl_data_source *source, uint32_t action)
+{
+	if (action & source->possible_actions)
+		wl_data_source_send_complete(&source->resource, action);
+	else
+		wl_data_source_send_complete(&source->resource, WL_DATA_OFFER_DND_ACTION_IGNORE);
+}
+
+static void
 create_data_source(struct wl_client *client,
 		   struct wl_resource *resource, uint32_t id)
 {
@@ -470,6 +506,9 @@ create_data_source(struct wl_client *client,
 	source->accept = client_source_accept;
 	source->send = client_source_send;
 	source->cancel = client_source_cancel;
+	source->complete = client_source_complete;
+	source->possible_actions = WL_DATA_OFFER_DND_ACTION_IGNORE;
+	source->accepted = 0;
 
 	wl_array_init(&source->mime_types);
 	wl_client_add_resource(client, &source->resource);
diff --git a/src/wayland-server.h b/src/wayland-server.h
index c7369eb..5b38cae 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -269,12 +269,16 @@ struct wl_data_offer {
 struct wl_data_source {
 	struct wl_resource resource;
 	struct wl_array mime_types;
+	uint32_t possible_actions;
+	int32_t accepted;
 
 	void (*accept)(struct wl_data_source *source,
 		       uint32_t serial, const char *mime_type);
 	void (*send)(struct wl_data_source *source,
 		     const char *mime_type, int32_t fd);
 	void (*cancel)(struct wl_data_source *source);
+	void (*complete)(struct wl_data_source *source,
+				 uint32_t action);
 };
 
 struct wl_pointer {
-- 
1.8.1.5



More information about the wayland-devel mailing list