Hey!,

On Tue, Dec 22, 2015 at 5:25 AM, Jonas Ådahl <[email protected]> wrote:
> On Tue, Dec 22, 2015 at 02:33:28AM +0100, Carlos Garnacho wrote:
>> The policy in weston in order to determine the chosen DnD action is
>> deliberately simple, and is probably the minimals that any compositor
>> should be doing here.
>>
>> Besides honoring the set_actions requests on both wl_data_source and
>> wl_data_offer, weston now will emit the newly added "action" events
>> notifying both source and dest of the chosen action.
>>
>> The "dnd" client has been updated too (although minimally), so it
>> notifies the compositor of a "move" action on both sides.
>
> dnd.c needs to be updated to require version 3 to function, since you
> now depend on it.

Right

>
>>
>> Changes since v4:
>>   - Added compositor-side version checks. Spaces vs tabs fixes.
>>     Fixed resource versioning. Initialized new weston_data_source/offer
>>     fields.
>>
>> Changes since v3:
>>   - Put data_source.action to use in the dnd client, now updates
>>     the dnd surface like data_source.target events do.
>>
>> Changes since v2:
>>   - Split from DnD progress notification changes.
>>
>> Changes since v1:
>>   - Updated to v2 of DnD actions protocol changes, implement
>>     wl_data_offer.source_actions.
>>   - Fixed coding style issues.
>>
>> Signed-off-by: Carlos Garnacho <[email protected]>
>> Reviewed-by: Michael Catanzaro <[email protected]>
>
> Mostly looks good, with a few nits below and one above. I suspect some
> changes are needed depending on how the "ask" action should be
> interpeted, so I'll give my RB when that has been cleared out.
>
>> ---
>>  clients/dnd.c     |  32 ++++++++++++++---
>>  clients/window.c  |  25 +++++++++++++
>>  src/compositor.h  |   4 +++
>>  src/data-device.c | 104 
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>  4 files changed, 157 insertions(+), 8 deletions(-)
>>
>> diff --git a/clients/dnd.c b/clients/dnd.c
>> index 48111d9..ddf3fcc 100644
>> --- a/clients/dnd.c
>> +++ b/clients/dnd.c
>> @@ -72,6 +72,7 @@ struct dnd_drag {
>>       struct item *item;
>>       int x_offset, y_offset;
>>       int width, height;
>> +     uint32_t dnd_action;
>>       const char *mime_type;
>>
>>       struct wl_surface *drag_surface;
>> @@ -266,16 +267,13 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
>>  }
>>
>>  static void
>> -data_source_target(void *data,
>> -                struct wl_data_source *source, const char *mime_type)
>> +dnd_drag_update_surface(struct dnd_drag *dnd_drag)
>>  {
>> -     struct dnd_drag *dnd_drag = data;
>>       struct dnd *dnd = dnd_drag->dnd;
>>       cairo_surface_t *surface;
>>       struct wl_buffer *buffer;
>>
>> -     dnd_drag->mime_type = mime_type;
>> -     if (mime_type)
>> +     if (dnd_drag->mime_type && dnd_drag->dnd_action)
>>               surface = dnd_drag->opaque;
>>       else
>>               surface = dnd_drag->translucent;
>> @@ -288,6 +286,16 @@ data_source_target(void *data,
>>  }
>>
>>  static void
>> +data_source_target(void *data,
>> +                struct wl_data_source *source, const char *mime_type)
>> +{
>> +     struct dnd_drag *dnd_drag = data;
>> +
>> +     dnd_drag->mime_type = mime_type;
>> +     dnd_drag_update_surface(dnd_drag);
>> +}
>> +
>> +static void
>>  data_source_send(void *data, struct wl_data_source *source,
>>                const char *mime_type, int32_t fd)
>>  {
>> @@ -360,12 +368,22 @@ data_source_drag_finished(void *data, struct 
>> wl_data_source *source)
>>       dnd_drag_destroy(dnd_drag);
>>  }
>>
>> +static void
>> +data_source_action(void *data, struct wl_data_source *source, uint32_t 
>> dnd_action)
>> +{
>> +     struct dnd_drag *dnd_drag = data;
>> +
>> +     dnd_drag->dnd_action = dnd_action;
>> +     dnd_drag_update_surface(dnd_drag);
>> +}
>> +
>>  static const struct wl_data_source_listener data_source_listener = {
>>       data_source_target,
>>       data_source_send,
>>       data_source_cancelled,
>>       data_source_drop_performed,
>>       data_source_drag_finished,
>> +     data_source_action,
>>  };
>>
>>  static cairo_surface_t *
>> @@ -428,6 +446,8 @@ create_drag_source(struct dnd *dnd,
>>               dnd_drag->item = item;
>>               dnd_drag->x_offset = x - item->x;
>>               dnd_drag->y_offset = y - item->y;
>> +             dnd_drag->dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
>> +             dnd_drag->mime_type = NULL;
>>
>>               for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
>>                       if (item == dnd->items[i]){
>> @@ -461,6 +481,8 @@ create_drag_source(struct dnd *dnd,
>>                                         window_get_wl_surface(dnd->window),
>>                                         dnd_drag->drag_surface,
>>                                         serial);
>> +             wl_data_source_set_actions(dnd_drag->data_source,
>> +                                        
>> WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
>>
>>               dnd_drag->opaque =
>>                       create_drag_icon(dnd_drag, item, x, y, 1);
>> diff --git a/clients/window.c b/clients/window.c
>> index db96185..9c67b91 100644
>> --- a/clients/window.c
>> +++ b/clients/window.c
>> @@ -3362,6 +3362,8 @@ struct data_offer {
>>       int fd;
>>       data_func_t func;
>>       int32_t x, y;
>> +     uint32_t dnd_action;
>> +     uint32_t source_actions;
>>       void *user_data;
>>  };
>>
>> @@ -3375,8 +3377,26 @@ data_offer_offer(void *data, struct wl_data_offer 
>> *wl_data_offer, const char *ty
>>       *p = strdup(type);
>>  }
>>
>> +static void
>> +data_offer_source_actions(void *data, struct wl_data_offer *wl_data_offer, 
>> uint32_t source_actions)
>> +{
>> +     struct data_offer *offer = data;
>> +
>> +     offer->source_actions = source_actions;
>> +}
>> +
>> +static void
>> +data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t 
>> dnd_action)
>> +{
>> +     struct data_offer *offer = data;
>> +
>> +     offer->dnd_action = dnd_action;
>> +}
>> +
>>  static const struct wl_data_offer_listener data_offer_listener = {
>>       data_offer_offer,
>> +     data_offer_source_actions,
>> +     data_offer_action
>>  };
>>
>>  static void
>> @@ -3440,6 +3460,11 @@ data_device_enter(void *data, struct wl_data_device 
>> *data_device,
>>               *p = NULL;
>>
>>               types_data = input->drag_offer->types.data;
>> +             wl_data_offer_set_actions(offer,
>> +                                       
>> WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
>> +                                       
>> WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
>> +                                       
>> WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
>> +
>>       } else {
>>               input->drag_offer = NULL;
>>               types_data = NULL;
>> diff --git a/src/compositor.h b/src/compositor.h
>> index 96a7b0d..9aa0150 100644
>> --- a/src/compositor.h
>> +++ b/src/compositor.h
>> @@ -298,6 +298,8 @@ struct weston_data_offer {
>>       struct wl_resource *resource;
>>       struct weston_data_source *source;
>>       struct wl_listener source_destroy_listener;
>> +     uint32_t dnd_actions;
>> +     uint32_t preferred_dnd_action;
>
> Shouldn't "preferred_dnd_action" be a enum wl_data_device_action, since
> it's not a mask?

Right, changed locally.

>
>>  };
>>
>>  struct weston_data_source {
>> @@ -306,6 +308,8 @@ struct weston_data_source {
>>       struct wl_array mime_types;
>>       struct weston_data_offer *offer;
>>       bool accepted;
>> +     uint32_t dnd_actions;
>> +     uint32_t current_dnd_action;
>
> Same here regarding "current_dnd_action".
>
>>
>>       void (*accept)(struct weston_data_source *source,
>>                      uint32_t serial, const char *mime_type);
>> diff --git a/src/data-device.c b/src/data-device.c
>> index d5b8f02..045cef5 100644
>> --- a/src/data-device.c
>> +++ b/src/data-device.c
>> @@ -101,7 +101,8 @@ data_offer_notify_finish(struct weston_data_offer *offer)
>>           offer->source->offer == offer &&
>>           wl_resource_get_version(offer->source->resource) >=
>>           WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
>> -             if (offer->source->accepted)
>> +             if (offer->source->accepted &&
>> +                 offer->source->current_dnd_action)
>>                       
>> wl_data_source_send_dnd_finished(offer->source->resource);
>>               else
>>                       wl_data_source_send_cancelled(offer->source->resource);
>> @@ -110,6 +111,72 @@ data_offer_notify_finish(struct weston_data_offer 
>> *offer)
>>       }
>>  }
>>
>> +static uint32_t
>> +data_offer_choose_action(struct weston_data_offer *offer)
>> +{
>> +     uint32_t available_actions, preferred_action = 0;
>> +     uint32_t source_actions, offer_actions;
>> +
>> +     if (wl_resource_get_version (offer->resource) >=
>
> No space between function name and (.
>
>> +         WL_DATA_OFFER_ACTION_SINCE_VERSION) {
>> +             offer_actions = offer->dnd_actions;
>> +             preferred_action = offer->preferred_dnd_action;
>> +     } else {
>> +             offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
>> +     }
>> +
>> +     if (wl_resource_get_version (offer->source->resource) >=
>
> No space between function name and (.
>
>> +         WL_DATA_SOURCE_ACTION_SINCE_VERSION)
>> +             source_actions = offer->source->dnd_actions;
>> +     else
>> +             source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
>> +
>> +     available_actions = offer_actions & source_actions;
>> +
>> +     if (!available_actions)
>> +             return 0;
>
> WL_DATA_DEVICE_ACTION_NONE.
>
>> +
>> +     /* If the dest side has a preferred DnD action, use it */
>> +     if ((preferred_action & available_actions) != 0)
>> +             return preferred_action;
>> +
>> +     /* Use the first found action, in bit order */
>> +     return 1 << (ffs(available_actions) - 1);
>> +}
>> +
>> +static void
>> +data_offer_update_action(struct weston_data_offer *offer)
>> +{
>> +     uint32_t action;
>> +
>> +     action = data_offer_choose_action(offer);
>> +
>> +     if (offer->source->current_dnd_action == action)
>> +             return;
>> +
>> +     offer->source->current_dnd_action = action;
>> +
>> +     if (wl_resource_get_version (offer->source->resource) >=
>
> No space between function name and (.
>
>> +         WL_DATA_SOURCE_ACTION_SINCE_VERSION)
>> +             wl_data_source_send_action(offer->source->resource, action);
>> +
>> +     if (wl_resource_get_version (offer->resource) >=
>
> No space between function name and (.
>
>> +         WL_DATA_OFFER_ACTION_SINCE_VERSION)
>> +             wl_data_offer_send_action(offer->resource, action);
>> +}
>> +
>> +static void
>> +data_offer_set_actions(struct wl_client *client,
>> +                    struct wl_resource *resource,
>> +                    uint32_t dnd_actions, uint32_t preferred_action)
>> +{
>> +     struct weston_data_offer *offer = wl_resource_get_user_data(resource);
>
> Should we teminate the client if this is called after a receive or
> finish?

After receive it's still acceptable (eg. the drop destination may
preemptively fetch all data mid-drag, before even taking a decision,
actually this is key to webkit2), it is a good idea though to make it
an error if called after finish. Actually, this should also be
mentioned in wl_data_offer.receive docs, I'm adding the following
blurb to wayland 1/2:

   This request may happen multiple times for different mimetypes, both
   before and after wl_data_device.drop. Drag-and-drop destination clients
   may preemptively fetch data or examine it more closely to determine
   acceptance.

>
>> +
>> +     offer->dnd_actions = dnd_actions;
>> +     offer->preferred_dnd_action = preferred_action;
>
> Should we do any input validation? I.e. trying to set invalid actions or
> setting a preferred action that is actually multiple actions, should it
> disconnect the client?

Yeah probably... I'll add that error too. The bitmasks were originally
untouched in order to cater for extra action bits, that makes less
sense now.

Cheers,
  Carlos
_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to