[PATCH 1/2] ecore_wayland: Add Copy and Paste support

zhiwen.wu at linux.intel.com zhiwen.wu at linux.intel.com
Thu Jul 26 02:18:29 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