[PATCH weston v3] data-device: Implement DnD actions
Carlos Garnacho
carlosg at gnome.org
Fri Oct 30 14:06:36 PDT 2015
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.
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 <carlosg at gnome.org>
---
clients/dnd.c | 12 +++++++++
clients/window.c | 25 +++++++++++++++++++
src/compositor.h | 4 +++
src/data-device.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 113 insertions(+), 3 deletions(-)
diff --git a/clients/dnd.c b/clients/dnd.c
index 6c2ed57..75a14f1 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;
@@ -360,12 +361,21 @@ data_source_drag_finished(void *data, struct wl_data_source *source)
destroy_dnd_drag(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;
+}
+
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 *
@@ -461,6 +471,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 24aa517..146d4a7 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_COPY);
+
} else {
input->drag_offer = NULL;
types_data = NULL;
diff --git a/src/compositor.h b/src/compositor.h
index 18266ef..b1c3305 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;
};
struct weston_data_source {
@@ -306,6 +308,8 @@ struct weston_data_source {
struct wl_array mime_types;
struct weston_data_offer *offer;
int accepted;
+ uint32_t dnd_actions;
+ uint32_t 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 4be392d..e81e8b2 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -94,10 +94,56 @@ data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
wl_resource_destroy(resource);
}
+static uint32_t
+data_offer_choose_action(struct weston_data_offer *offer)
+{
+ uint32_t available_actions;
+
+ available_actions = offer->dnd_actions & offer->source->dnd_actions;
+
+ if (!available_actions)
+ return 0;
+
+ /* If the dest side has a preferred DnD action, use it */
+ if ((offer->preferred_dnd_action & available_actions) != 0)
+ return offer->preferred_dnd_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;
+ wl_data_source_send_action(offer->source->resource, action);
+ 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);
+
+ offer->dnd_actions = dnd_actions;
+ offer->preferred_dnd_action = preferred_action;
+ data_offer_update_action(offer);
+}
+
static const struct wl_data_offer_interface data_offer_interface = {
data_offer_accept,
data_offer_receive,
data_offer_destroy,
+ data_offer_set_actions
};
static void
@@ -107,7 +153,8 @@ destroy_data_offer(struct wl_resource *resource)
if (offer->source) {
if (offer->source->offer == offer) {
- 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);
@@ -144,7 +191,7 @@ weston_data_source_send_offer(struct weston_data_source *source,
offer->resource =
wl_resource_create(wl_resource_get_client(target),
- &wl_data_offer_interface, 1, 0);
+ &wl_data_offer_interface, 3, 0);
if (offer->resource == NULL) {
free(offer);
return NULL;
@@ -165,6 +212,7 @@ weston_data_source_send_offer(struct weston_data_source *source,
source->offer = offer;
source->accepted = 0;
+ data_offer_update_action(offer);
return offer->resource;
}
@@ -191,9 +239,30 @@ 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 dnd_actions)
+{
+ struct weston_data_source *source =
+ wl_resource_get_user_data(resource);
+
+ if (source->dnd_actions == dnd_actions)
+ return;
+
+ source->dnd_actions = dnd_actions;
+
+ if (source->offer) {
+ wl_data_offer_send_source_actions(source->offer->resource,
+ dnd_actions);
+ data_offer_update_action(source->offer);
+ }
+}
+
static struct wl_data_source_interface data_source_interface = {
data_source_offer,
- data_source_destroy
+ data_source_destroy,
+ data_source_set_actions
};
static void
--
2.5.0
More information about the wayland-devel
mailing list