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

Giulio Camuffo giuliocamuffo at gmail.com
Wed Mar 13 07:48:15 PDT 2013


2013/3/13 Jason Ekstrand <jason at jlekstrand.net>:
> On Wed, Mar 13, 2013 at 4:59 AM, Giulio Camuffo <giuliocamuffo at gmail.com> wrote:
>> 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
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
> In general, I like it and we've already talked about it some.  I still
> have two questions regarding the actions:
>
> 1. What exactly does the IGNORE action mean?  I think it's probably
> ok, but needs better documentation.

It means the target should do nothing with the data.

>
> 2. What actions do other toolkits (besides Qt) support?  With that,
> how should we expect toolkits that only support a subset of those
> actions (or others not in that list) to handle actions?  For example,
> a quick scan through android d&d seems to indicate that they don't
> really have actions at all.  What actions should an android app
> accept? what actions should it offer?

Well, the actions are just hints.  It depends on the app, but it
should offer an action which makes sense. Like weston's dnd client: it
doesn't need to offer and accept any action but it makes sense for it
to use MOVE.

>
> From a quick scan of the GTK documentation, it looks like theirs is
> similar, but they have a few more actions. Do we want to handle tese
> as well?
>
> https://developer.gnome.org/gdk/unstable/gdk-Drag-and-Drop.html#GdkDragAction

DEFAULT seems like it's IGNORE. I'm not sure about the other two.
If the target wants to ask the user it can just look what actions the
source support and make the user choose between these. Then it can
accept the selected one.
Maybe PRIVATE makes sense, but i'd like to see some usecase.


>
> Really, I think what you've done so far is fantastic. I'm just trying
> to bring this up now so that we can plan for the future a bit before
> it gets codified in the wayland protocol.
>
> Thanks,
> --Jason Ekstrand


More information about the wayland-devel mailing list