[PATCH 1/2 v2] ecore_wayland: Add Copy and Paste support
zhiwen.wu at linux.intel.com
zhiwen.wu at linux.intel.com
Wed Aug 1 21:39:58 PDT 2012
From: Alex Wu <zhiwen.wu at linux.intel.com>
Add a global Ecore_Wl_Dnd object to handle copy and paste. I think
it is more appropriate to name this struct Ecore_Wl_Selection, which
is responsible for both dnd and cnp. This patch just cover the copy
and paste and not support "clear clipboard", due to wayland has no
way to do that.
---
trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h | 25 ++
trunk/ecore/src/lib/ecore_wayland/ecore_wl.c | 14 +
trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c | 271 ++++++++++++++++++++
trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c | 16 ++
.../ecore/src/lib/ecore_wayland/ecore_wl_private.h | 14 +
5 files changed, 340 insertions(+)
diff --git a/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h b/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h
index 5ff3293..e380d46 100644
--- a/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h
+++ b/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h
@@ -35,6 +35,7 @@ typedef struct _Ecore_Wl_Input Ecore_Wl_Input;
# ifndef _ECORE_WAYLAND_WINDOW_PREDEF
typedef struct _Ecore_Wl_Window Ecore_Wl_Window;
# endif
+typedef struct _Ecore_Wl_Dnd Ecore_Wl_Dnd;
typedef struct _Ecore_Wl_Dnd_Source Ecore_Wl_Dnd_Source;
typedef struct _Ecore_Wl_Dnd_Target Ecore_Wl_Dnd_Target;
@@ -47,6 +48,8 @@ typedef struct _Ecore_Wl_Event_Dnd_Enter Ecore_Wl_Event_Dnd_Enter;
typedef struct _Ecore_Wl_Event_Dnd_Position Ecore_Wl_Event_Dnd_Position;
typedef struct _Ecore_Wl_Event_Dnd_Leave Ecore_Wl_Event_Dnd_Leave;
typedef struct _Ecore_Wl_Event_Dnd_Drop Ecore_Wl_Event_Dnd_Drop;
+typedef struct _Ecore_Wl_Event_Data_Source_Send Ecore_Wl_Event_Data_Source_Send;
+typedef struct _Ecore_Wl_Event_Selection_Data_Ready Ecore_Wl_Event_Selection_Data_Ready;
typedef struct _Ecore_Wl_Event_Interfaces_Bound Ecore_Wl_Event_Interfaces_Bound;
enum _Ecore_Wl_Window_Type
@@ -142,6 +145,7 @@ struct _Ecore_Wl_Input
Ecore_Wl_Dnd_Source *drag_source;
Ecore_Wl_Dnd_Source *selection_source;
+ Ecore_Wl_Dnd *dnd;
struct
{
@@ -269,6 +273,19 @@ struct _Ecore_Wl_Event_Dnd_Drop
} position;
};
+struct _Ecore_Wl_Event_Data_Source_Send
+{
+ char *type;
+ int fd;
+};
+
+struct _Ecore_Wl_Event_Selection_Data_Ready
+{
+ char *data;
+ int len;
+ Eina_Bool done;
+};
+
struct _Ecore_Wl_Event_Interfaces_Bound
{
Eina_Bool compositor : 1;
@@ -299,6 +316,10 @@ EAPI extern int ECORE_WL_EVENT_DND_ENTER;
EAPI extern int ECORE_WL_EVENT_DND_POSITION;
EAPI extern int ECORE_WL_EVENT_DND_LEAVE;
EAPI extern int ECORE_WL_EVENT_DND_DROP;
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_TARGET;
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_SEND;
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED;
+EAPI extern int ECORE_WL_EVENT_SELECTION_DATA_READY;
EAPI extern int ECORE_WL_EVENT_INTERFACES_BOUND;
EAPI int ecore_wl_init(const char *name);
@@ -343,5 +364,9 @@ EAPI void ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *s
EAPI void ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name);
EAPI void ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win);
EAPI void ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent);
+EAPI Eina_Bool ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered);
+EAPI Eina_Bool ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type);
+EAPI Ecore_Wl_Dnd *ecore_wl_dnd_get();
+EAPI Eina_Bool ecore_wl_dnd_start_drag();
#endif
diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c
index c21c102..eef87bb 100644
--- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c
+++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c
@@ -29,6 +29,10 @@ EAPI int ECORE_WL_EVENT_DND_ENTER = 0;
EAPI int ECORE_WL_EVENT_DND_POSITION = 0;
EAPI int ECORE_WL_EVENT_DND_LEAVE = 0;
EAPI int ECORE_WL_EVENT_DND_DROP = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_TARGET = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_SEND = 0;
+EAPI int ECORE_WL_EVENT_SELECTION_DATA_READY = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = 0;
EAPI int ECORE_WL_EVENT_INTERFACES_BOUND = 0;
/**
@@ -95,6 +99,10 @@ ecore_wl_init(const char *name)
ECORE_WL_EVENT_DND_POSITION = ecore_event_type_new();
ECORE_WL_EVENT_DND_LEAVE = ecore_event_type_new();
ECORE_WL_EVENT_DND_DROP = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_TARGET = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_SEND = ecore_event_type_new();
+ ECORE_WL_EVENT_SELECTION_DATA_READY = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = ecore_event_type_new();
ECORE_WL_EVENT_INTERFACES_BOUND = ecore_event_type_new();
}
@@ -479,3 +487,9 @@ _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd)
return EINA_TRUE;
}
+
+struct wl_data_source *
+_ecore_wl_create_data_source(Ecore_Wl_Display *ewd)
+{
+ return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager);
+}
diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c
index 164693f..ac6f2a3 100644
--- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c
+++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c
@@ -2,18 +2,289 @@
# include <config.h>
#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+#include <errno.h>
+#define _GNU_SOURCE
+#include <unistd.h>
#include "ecore_wl_private.h"
+struct task
+{
+ void *data;
+ Ecore_Fd_Cb cb;
+};
+
+struct read_ctx
+{
+ int epoll_fd;
+ struct epoll_event *ep;
+};
+
+extern Ecore_Wl_Dnd *glb_dnd;
/* local function prototypes */
static void _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type);
static void _ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event);
+static void _ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type);
+static void _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd);
+static void _ecore_wl_dnd_data_source_cancelled(void *data, struct wl_data_source *source);
+
/* wayland listeners */
static const struct wl_data_offer_listener _ecore_wl_data_offer_listener =
{
_ecore_wl_dnd_offer,
};
+static const struct wl_data_source_listener _ecore_wl_data_source_listener =
+{
+ _ecore_wl_dnd_data_source_target,
+ _ecore_wl_dnd_data_source_send,
+ _ecore_wl_dnd_data_source_cancelled
+};
+
+static void
+_ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type)
+{
+ //TODO:
+}
+
+static void
+_ecore_wl_dnd_cb_data_source_send_free(void *data __UNUSED__, void *event)
+{
+ Ecore_Wl_Event_Data_Source_Send *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = event)) return;
+
+ free(ev->type);
+ free(ev);
+}
+
+static void
+_ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source __UNUSED__, const char *mime_type, int32_t fd)
+{
+ Ecore_Wl_Event_Data_Source_Send *event;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!data) return;
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Data_Source_Send)))) return;
+
+ event->type = strdup(mime_type);
+ event->fd = fd;
+
+ ecore_event_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, event, _ecore_wl_dnd_cb_data_source_send_free, NULL);
+}
+
+EAPI Ecore_Wl_Dnd *
+ecore_wl_dnd_get()
+{
+ return glb_dnd;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_start_drag(Ecore_Wl_Dnd *dnd)
+{
+ //TODO:
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered)
+{
+ char **p, **type;
+
+ dnd->data_source = _ecore_wl_create_data_source(dnd->ewd);
+
+ /* free old types */
+ if (dnd->types_offered.data)
+ {
+ wl_array_for_each(p, &dnd->types_offered)
+ free(*p);
+ wl_array_release(&dnd->types_offered);
+ wl_array_init(&dnd->types_offered);
+ }
+
+ for (type = types_offered; *type; type++)
+ {
+ p = wl_array_add(&dnd->types_offered, sizeof(*p));
+ *p = strdup(*type);
+ wl_data_source_offer(dnd->data_source, *p);
+ }
+
+ wl_data_source_add_listener(dnd->data_source, &_ecore_wl_data_source_listener, dnd);
+
+ _ecore_wl_input_set_selection(dnd->input, dnd->data_source);
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_wl_dnd_cb_selection_data_ready_free(void *data __UNUSED__, void *event)
+{
+ Ecore_Wl_Event_Selection_Data_Ready *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = event)) return;
+
+ free(ev->data);
+ free(ev);
+}
+
+static Eina_Bool
+read_data_func(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
+{
+ int len;
+ char buffer[4096];
+ Ecore_Wl_Dnd_Source *source;
+ Ecore_Wl_Event_Selection_Data_Ready *event;
+ Eina_Bool ret;
+
+ source = data;
+
+ len = read(source->fd, buffer, sizeof buffer);
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Selection_Data_Ready)))) return ECORE_CALLBACK_CANCEL;
+
+ if (len == 0 || len == -1)
+ {
+ close(source->fd);
+ _ecore_wl_dnd_del(source);
+ event->done = EINA_TRUE;
+ event->data = NULL;
+ event->len = 0;
+ ret = ECORE_CALLBACK_CANCEL;
+ }
+ else
+ {
+ event->data = malloc(len + 1);
+ if (!event->data) return ECORE_CALLBACK_CANCEL;
+ strncpy(event->data, buffer, len);
+ event->data[len] = '\0';
+ event->len = len;
+ event->done = EINA_FALSE;
+ ret = ECORE_CALLBACK_RENEW;
+ }
+
+ ecore_event_add(ECORE_WL_EVENT_SELECTION_DATA_READY, event, _ecore_wl_dnd_cb_selection_data_ready_free, NULL);
+ return ret;
+}
+
+
+static Eina_Bool
+_idler_cb(void *data)
+{
+ struct read_ctx *ctx = data;
+ struct task *task;
+ int count, i;
+
+ count = epoll_wait(ctx->epoll_fd, ctx->ep, 1, 0);
+ for (i = 0; i < count; i++)
+ {
+ task = ctx->ep->data.ptr;
+ if (task->cb(task->data, NULL) == ECORE_CALLBACK_CANCEL)
+ {
+ free(ctx->ep);
+ free(task);
+ free(ctx);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type)
+{
+ int p[2];
+
+ if (pipe2(p, O_CLOEXEC) == -1)
+ return;
+
+ wl_data_offer_receive(source->offer, type, p[1]);
+ close(p[1]);
+
+ /* Due to http://trac.enlightenment.org/e/ticket/1208,
+ * use epoll and idle handler instead of ecore_main_fd_handler_add() */
+ int epoll_fd;
+ struct epoll_event *ep = NULL;
+ struct task *task = NULL;
+ struct read_ctx *read_ctx = NULL;
+
+ ep = calloc(1, sizeof(struct epoll_event));
+ if (!ep) goto err;
+
+ task = calloc(1, sizeof(struct task));
+ if (!task) goto err;
+
+ read_ctx = calloc(1, sizeof(struct read_ctx));
+ if (!read_ctx) goto err;
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) goto err;
+
+ task->data = source;
+ task->cb = read_data_func;
+ ep->events = EPOLLIN;
+ ep->data.ptr = task;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, p[0], ep) < 0) goto err;
+
+ read_ctx->epoll_fd = epoll_fd;
+ read_ctx->ep = ep;
+
+ if (ecore_idler_add(_idler_cb, read_ctx) == NULL) goto err;
+
+ source->refcount++;
+ source->fd = p[0];
+ return;
+
+err:
+ if (ep) free(ep);
+ if (task) free(task);
+ if (read_ctx) free(read_ctx);
+ close(p[0]);
+ return;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type)
+{
+ char **p;
+ Ecore_Wl_Input *input;
+
+ input = dnd->input;
+
+ if (input->selection_source == NULL)
+ return EINA_FALSE;
+
+ wl_array_for_each(p, &input->selection_source->types)
+ if (strcmp(type, *p) == 0)
+ break;
+
+ if (*p == NULL)
+ return EINA_FALSE;
+
+ _ecore_wl_dnd_source_receive_data(input->selection_source, type);
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_wl_dnd_data_source_cancelled(void *data __UNUSED__, struct wl_data_source *source)
+{
+ wl_data_source_destroy(source);
+}
+
void
_ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer)
{
diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c
index 9d82f60..355f58f 100644
--- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c
+++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c
@@ -38,6 +38,8 @@
#define MOD_ALT_MASK 0x02
#define MOD_CONTROL_MASK 0x04
+Ecore_Wl_Dnd *glb_dnd = NULL;
+
/* local function prototypes */
static void _ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps);
@@ -238,6 +240,14 @@ _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id)
wl_compositor_create_surface(_ecore_wl_disp->wl.compositor);
ewd->input = input;
+
+ /* create Ecore_Wl_Dnd */
+ if (glb_dnd == NULL)
+ if (!(glb_dnd = calloc(1, sizeof(Ecore_Wl_Dnd)))) return;
+ glb_dnd->ewd = ewd;
+ glb_dnd->input = input;
+ input->dnd = glb_dnd;
+ wl_array_init(&glb_dnd->types_offered);
}
void
@@ -1113,3 +1123,9 @@ _ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int v
ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
}
+
+void
+_ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source)
+{
+ wl_data_device_set_selection(input->data_device, source, input->display->serial);
+}
diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h
index 63a5f12..29555ee 100644
--- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h
+++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h
@@ -50,6 +50,18 @@ extern Ecore_Wl_Display *_ecore_wl_disp;
# endif
# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_wl_log_dom, __VA_ARGS__)
+struct _Ecore_Wl_Dnd
+{
+ Ecore_Wl_Display *ewd;
+ Ecore_Wl_Input *input;
+
+ /* As provider */
+ struct wl_data_source *data_source;
+ struct wl_array types_offered;
+
+ /* TODO: dnd specific fields */
+};
+
struct _Ecore_Wl_Dnd_Source
{
struct wl_data_offer *offer;
@@ -77,6 +89,7 @@ void _ecore_wl_output_del(Ecore_Wl_Output *output);
void _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id);
void _ecore_wl_input_del(Ecore_Wl_Input *input);
void _ecore_wl_input_pointer_xy_get(int *x, int *y);
+void _ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source);
void _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device, struct wl_data_offer *offer);
void _ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, struct wl_surface *surface, int x, int y, struct wl_data_offer *offer);
@@ -86,4 +99,5 @@ void _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device __UNUSED_
void _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer);
void _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source);
+struct wl_data_source *_ecore_wl_create_data_source(Ecore_Wl_Display *ewd);
#endif
--
1.7.9.5
More information about the wayland-devel
mailing list