discomfitor pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=8e211f1950aff7bbafdfed32989a164d6e74fa59

commit 8e211f1950aff7bbafdfed32989a164d6e74fa59
Author: Mike Blumenkrantz <zm...@osg.samsung.com>
Date:   Fri Aug 7 21:06:47 2015 -0400

    implement wl->x11 dnd operations
    
    seems to work fine, large selection data (ref T2330) still untested
---
 src/bin/e_comp_wl_data.c   | 108 ++++++++++++++++++++--------
 src/bin/e_dnd.c            |   5 +-
 src/modules/xwayland/dnd.c | 172 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 251 insertions(+), 34 deletions(-)

diff --git a/src/bin/e_comp_wl_data.c b/src/bin/e_comp_wl_data.c
index d42fb0c..3de9920 100644
--- a/src/bin/e_comp_wl_data.c
+++ b/src/bin/e_comp_wl_data.c
@@ -281,22 +281,40 @@ _e_comp_wl_data_device_drag_finished(E_Drag *drag, int 
dropped)
    evas_object_hide(o);
    evas_object_pass_events_set(o, 1);
    if (e_comp->wl_comp_data->drag != drag) return;
+   e_comp->wl_comp_data->drag = NULL;
+   e_comp->wl_comp_data->drag_client = NULL;
+   e_screensaver_inhibit_toggle(0);
    if (e_comp->wl_comp_data->selection.target && (!dropped))
      {
-        struct wl_resource *res;
-
-        res = 
e_comp_wl_data_find_for_client(wl_resource_get_client(e_comp->wl_comp_data->selection.target->comp_data->surface));
-        if (res)
+#ifndef HAVE_WAYLAND_ONLY
+        if (e_client_has_xwindow(e_comp->wl_comp_data->selection.target))
+          {
+             
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->selection.target),
+               ECORE_X_ATOM_XDND_DROP, ECORE_X_EVENT_MASK_NONE,
+               e_comp->cm_selection, 0, ecore_x_current_time_get(), 0, 0);
+          }
+        else
+#endif
           {
-             wl_data_device_send_drop(res);
-             wl_data_device_send_leave(res);
+             struct wl_resource *res;
+
+             res = 
e_comp_wl_data_find_for_client(wl_resource_get_client(e_comp->wl_comp_data->selection.target->comp_data->surface));
+             if (res)
+               {
+                  wl_data_device_send_drop(res);
+                  wl_data_device_send_leave(res);
+               }
+#ifndef HAVE_WAYLAND_ONLY
+             if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && e_comp_util_has_x())
+               {
+                  ecore_x_selection_owner_set(0, ECORE_X_ATOM_SELECTION_XDND, 
0);
+                  ecore_x_window_hide(e_comp->cm_selection);
+               }
+#endif
+             e_comp->wl_comp_data->selection.target = NULL;
+             e_comp->wl_comp_data->drag_source = NULL;
           }
      }
-   e_comp->wl_comp_data->drag = NULL;
-   e_comp->wl_comp_data->drag_client = NULL;
-   e_comp->wl_comp_data->selection.target = NULL;
-   e_comp->wl_comp_data->drag_source = NULL;
-   e_screensaver_inhibit_toggle(0);
 }
 
 static void
@@ -346,6 +364,13 @@ _e_comp_wl_data_device_cb_drag_start(struct wl_client 
*client, struct wl_resourc
    if (ec)
      e_drag_object_set(e_comp->wl_comp_data->drag, ec->frame);
    e_drag_start(e_comp->wl_comp_data->drag, x, y);
+#ifndef HAVE_WAYLAND_ONLY
+   if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && e_comp_util_has_x())
+     {
+        ecore_x_window_show(e_comp->cm_selection);
+        ecore_x_selection_owner_set(e_comp->cm_selection, 
ECORE_X_ATOM_SELECTION_XDND, 0);
+     }
+#endif
    if (e_comp->wl_comp_data->ptr.ec)
      e_comp_wl_data_device_send_enter(e_comp->wl_comp_data->ptr.ec);
    e_screensaver_inhibit_toggle(1);
@@ -675,38 +700,60 @@ e_comp_wl_data_device_send_enter(E_Client *ec)
    uint32_t serial;
    int x, y;
 
-   if (e_client_has_xwindow(ec)) return;
-   data_device_res =
-      
e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
-   if (!data_device_res) return;
-
-   offer_res = e_comp_wl_data_device_send_offer(ec);
-   if (e_comp->wl_comp_data->selection.data_source && (!offer_res)) return;
+   if (e_client_has_xwindow(ec) && 
e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return;
+   if (!e_client_has_xwindow(ec))
+     {
+        data_device_res =
+              
e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
+        if (!data_device_res) return;
+        offer_res = e_comp_wl_data_device_send_offer(ec);
+        if (e_comp->wl_comp_data->drag_source && (!offer_res)) return;
+     }
    e_comp->wl_comp_data->selection.target = ec;
    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, 
_e_comp_wl_data_device_target_del, ec);
 
 #ifndef HAVE_WAYLAND_ONLY
-   if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client))
+   if (e_client_has_xwindow(ec))
      {
         int d1 = 0x5UL, d2, d3, d4;
+        E_Comp_Wl_Data_Source *source;
+        Eina_List *l;
 
         d2 = d3 = d4 = 0;
+        source = e_comp->wl_comp_data->drag_source;
+
+        if (eina_list_count(source->mime_types) > 3)
+          {
+             const char *type, *types[eina_list_count(source->mime_types)];
+             int i = 0;
 
-        if (e_comp->wl_comp_data->drag->num_types > 3)
-          d1 |= 0x1UL;
+             d1 |= 0x1UL;
+             EINA_LIST_FOREACH(source->mime_types, l, type)
+               types[i++] = type;
+             ecore_x_dnd_types_set(e_comp->cm_selection, types, i);
+          }
         else
           {
-             if (e_comp->wl_comp_data->drag->num_types > 0)
+             l = source->mime_types;
+
+             if (source->mime_types)
                d2 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[0]);
-             if (e_comp->wl_comp_data->drag->num_types > 1)
-               d3 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[1]);
-             if (e_comp->wl_comp_data->drag->num_types > 2)
-               d4 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[2]);
+             if (eina_list_count(source->mime_types) > 1)
+               {
+                  l = eina_list_next(l);
+                  d3 = ecore_x_atom_get(eina_list_data_get(l));
+               }
+             if (eina_list_count(source->mime_types) > 2)
+               {
+                  l = eina_list_next(l);
+                  d4 = ecore_x_atom_get(eina_list_data_get(l));
+               }
           }
 
-        
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
+        ecore_x_client_message32_send(e_client_util_win_get(ec),
           ECORE_X_ATOM_XDND_ENTER, ECORE_X_EVENT_MASK_NONE,
           e_comp->cm_selection, d1, d2, d3, d4);
+        return;
      }
 #endif
    x = wl_fixed_to_int(e_comp->wl_comp_data->ptr.x) - 
e_comp->wl_comp_data->selection.target->client.x;
@@ -721,16 +768,17 @@ e_comp_wl_data_device_send_leave(E_Client *ec)
 {
    struct wl_resource *res;
 
-   if (e_client_has_xwindow(ec)) return;
+   if (e_client_has_xwindow(ec) && 
e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return;
    evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_DEL, 
_e_comp_wl_data_device_target_del, ec);
    if (e_comp->wl_comp_data->selection.target == ec)
      e_comp->wl_comp_data->selection.target = NULL;
 #ifndef HAVE_WAYLAND_ONLY
-   if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client))
+   if (e_client_has_xwindow(ec))
      {
-        
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
+        ecore_x_client_message32_send(e_client_util_win_get(ec),
                ECORE_X_ATOM_XDND_LEAVE, ECORE_X_EVENT_MASK_NONE,
                e_comp->cm_selection, 0, 0, 0, 0);
+        return;
      }
 #endif
    res = 
e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
diff --git a/src/bin/e_dnd.c b/src/bin/e_dnd.c
index 167515e..ea74c1c 100644
--- a/src/bin/e_dnd.c
+++ b/src/bin/e_dnd.c
@@ -1218,8 +1218,9 @@ _e_dnd_cb_mouse_move(void *data EINA_UNUSED, int type 
EINA_UNUSED, void *event)
      {
         if (e_comp->wl_comp_data->drag != _drag_current) return 
ECORE_CALLBACK_RENEW;
         if (!e_comp->wl_comp_data->ptr.ec) return ECORE_CALLBACK_RENEW;
-        if (e_client_has_xwindow(e_comp->wl_comp_data->ptr.ec)) return 
ECORE_CALLBACK_RENEW;
-        
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
+        if (!e_client_has_xwindow(e_comp->wl_comp_data->ptr.ec)) return 
ECORE_CALLBACK_RENEW;
+        if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return 
ECORE_CALLBACK_RENEW;
+        
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->ptr.ec),
           ECORE_X_ATOM_XDND_POSITION, ECORE_X_EVENT_MASK_NONE,
           e_comp->cm_selection, 0, ((ev->x << 16) & 0xffff0000) | (ev->y & 
0xffff),
           ev->timestamp, ECORE_X_ATOM_XDND_ACTION_COPY);
diff --git a/src/modules/xwayland/dnd.c b/src/modules/xwayland/dnd.c
index 0b89dd4..6256e96 100644
--- a/src/modules/xwayland/dnd.c
+++ b/src/modules/xwayland/dnd.c
@@ -3,14 +3,39 @@
 #include <dlfcn.h>
 
 #define WL_TEXT_STR "text/plain;charset=utf-8"
+#define INCR_CHUNK_SIZE 1 << 17
 
 static void (*xconvertselection)(Ecore_X_Display *, Ecore_X_Atom, 
Ecore_X_Atom, Ecore_X_Atom, Ecore_X_Window, Ecore_X_Time);
 static Ecore_X_Atom string_atom;
 static Ecore_X_Atom xwl_dnd_atom;
+static Ecore_X_Atom timestamp_atom;
+static Ecore_X_Atom incr_atom;
+static Ecore_X_Atom int_atom;
 
 static int32_t cur_fd = -1;
 
 static Eina_List *handlers;
+static Eina_Hash *pipes;
+
+typedef struct
+{
+   Ecore_Fd_Handler *fdh;
+   E_Comp_Wl_Data_Source *source;
+   Ecore_X_Window win;
+   Ecore_X_Atom atom;
+   Ecore_X_Atom selection;
+   Ecore_X_Atom property;
+   Eina_Binbuf *buf;
+   Eina_Bool incr : 1;
+} Pipe;
+
+static void
+_pipe_free(Pipe *p)
+{
+   ecore_main_fd_handler_del(p->fdh);
+   eina_binbuf_free(p->buf);
+   free(p);
+}
 
 static void
 _xdnd_finish(Eina_Bool success)
@@ -20,6 +45,24 @@ _xdnd_finish(Eina_Bool success)
 }
 
 static void
+_incr_update(Pipe *p, Eina_Bool success)
+{
+   ecore_x_selection_notify_send(p->win, p->selection, p->atom, (!!success) * 
p->property, 0);
+}
+
+static void
+_incr_upload(Pipe *p)
+{
+   size_t size;
+
+   size = eina_binbuf_length_get(p->buf);
+   size = MIN(size, INCR_CHUNK_SIZE);
+   ecore_x_window_prop_property_set(p->win, p->property, p->atom, 8, 
(void*)eina_binbuf_string_get(p->buf), size);
+   eina_binbuf_free(p->buf);
+   p->buf = NULL;
+}
+
+static void
 _xwayland_dnd_finish(void)
 {
    ecore_x_window_hide(e_comp->cm_selection);
@@ -46,8 +89,6 @@ _xwayland_drop(E_Drag *drag, int dropped)
           {
              wl_data_device_send_drop(res);
              wl_data_device_send_leave(res);
-             
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
 ECORE_X_ATOM_XDND_DROP, ECORE_X_EVENT_MASK_NONE,
-               e_comp->cm_selection, 0, ecore_x_current_time_get(), 0, 0);
           }
         return;
      }
@@ -90,6 +131,7 @@ _xwayland_cancelled_send(E_Comp_Wl_Data_Source *source)
 static Eina_Bool
 _xwl_fixes_selection_notify(void *d EINA_UNUSED, int t EINA_UNUSED, 
Ecore_X_Event_Fixes_Selection_Notify *ev)
 {
+   if (ev->owner == e_comp->cm_selection) return ECORE_CALLBACK_RENEW;
    if (ev->atom == ECORE_X_ATOM_SELECTION_XDND)
      {
         if (ev->owner)
@@ -189,6 +231,125 @@ _xwl_selection_notify(void *d EINA_UNUSED, int t 
EINA_UNUSED, Ecore_X_Event_Sele
    return ECORE_CALLBACK_RENEW;
 }
 
+static Eina_Bool
+_xwl_pipe_read(void *data, Ecore_Fd_Handler *fdh)
+{
+   Pipe *p = data;
+   ssize_t len;
+   unsigned char *buf;
+
+   buf = malloc(INCR_CHUNK_SIZE);
+   len = read(ecore_main_fd_handler_fd_get(fdh), (void*)buf, INCR_CHUNK_SIZE);
+   if (len < 0)
+     {
+        _incr_update(p, 0);
+        eina_hash_del_by_key(pipes, &p->win);
+     }
+   if (len == INCR_CHUNK_SIZE)
+     {
+        p->buf = eina_binbuf_manage_new(buf, len, 0);
+        if (p->incr)
+          _incr_upload(p);
+        else
+          {
+             unsigned long size = INCR_CHUNK_SIZE;
+
+             p->incr = 1;
+             ecore_x_window_prop_property_set(p->win, p->atom, incr_atom, 32, 
&size, 1);
+             _incr_update(p, 1);
+          }
+        ecore_main_fd_handler_active_set(p->fdh, 0);
+        return ECORE_CALLBACK_RENEW;
+     }
+   if (len)
+     p->buf = eina_binbuf_manage_new(buf, len, 0);
+   _incr_upload(p);
+   if (p->incr)
+     ecore_main_fd_handler_active_set(p->fdh, 0);
+   else
+     {
+        _incr_update(p, 1);
+        eina_hash_del_by_key(pipes, &p->win);
+     }
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_xwl_selection_request(void *d EINA_UNUSED, int t EINA_UNUSED, 
Ecore_X_Event_Selection_Request *ev)
+{
+   E_Comp_Wl_Data_Source *source;
+   const char *type;
+   Eina_List *l;
+
+   if (!e_comp->wl_comp_data->drag_source) return ECORE_CALLBACK_RENEW;
+
+   source = e_comp->wl_comp_data->drag_source;
+   if (ev->target == ECORE_X_ATOM_SELECTION_TARGETS)
+     {
+        Ecore_X_Atom *atoms;
+        int i = 0;
+
+        atoms = alloca((2 + eina_list_count(source->mime_types)) * 
sizeof(void*));
+        EINA_LIST_FOREACH(source->mime_types, l, type)
+          atoms[i++] = ecore_x_atom_get(type);
+        atoms[i++] = timestamp_atom;
+        atoms[i++] = ECORE_X_ATOM_SELECTION_TARGETS;
+        ecore_x_window_prop_property_set(ev->requestor, ev->property, 
ECORE_X_ATOM_ATOM, 32, atoms, i);
+        ecore_x_selection_notify_send(ev->requestor, ev->selection, 
ev->target, ev->property, 0);
+     }
+   else if (ev->target == timestamp_atom)
+     {
+        Ecore_X_Time timestamp;
+
+        timestamp = ecore_x_current_time_get();
+        ecore_x_window_prop_property_set(ev->requestor, ev->property, 
int_atom, 32, (void*)&timestamp, 1);
+        ecore_x_selection_notify_send(ev->requestor, ev->selection, 
ev->target, ev->property, 0);
+     }
+   else
+     {
+        const char *name;
+        Pipe *p;
+
+        name = ecore_x_atom_name_get(ev->target);
+        EINA_LIST_FOREACH(source->mime_types, l, type)
+          if (eina_streq(name, type))
+            {
+               E_Client *ec;
+               int fds[2];
+
+               p = E_NEW(Pipe, 1);
+               socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, fds);
+               fcntl(fds[0], F_SETFL, O_NONBLOCK);
+               p->fdh = ecore_main_fd_handler_add(fds[0], ECORE_FD_READ, 
_xwl_pipe_read, p, NULL, NULL);
+               p->win = ev->requestor;
+               p->source = source;
+               wl_data_source_send_send(source->resource, type, dup(fds[1]));
+               close(fds[1]);
+               p->atom = ev->target;
+               p->selection = ev->selection;
+               p->property = ev->property;
+               ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ev->requestor);
+               if (ec && ec->override)
+                 ecore_x_window_sniff(ev->requestor);
+               eina_hash_add(pipes, &p->win, p);
+               break;
+            }
+     }
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_xwl_property(void *d EINA_UNUSED, int t EINA_UNUSED, 
Ecore_X_Event_Window_Property *ev)
+{
+   Pipe *p;
+
+   p = eina_hash_find(pipes, &ev->win);
+   if (!p) return ECORE_CALLBACK_RENEW;
+   /* FIXME: WHO FORGOT THE FUCKING STATE FLAG???? */
+   ecore_main_fd_handler_active_set(p->fdh, ECORE_FD_READ);
+   return ECORE_CALLBACK_RENEW;
+}
+
 EINTERN void
 dnd_init(void)
 {
@@ -196,9 +357,15 @@ dnd_init(void)
    ecore_x_fixes_selection_notification_request(ECORE_X_ATOM_SELECTION_XDND);
    E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, 
_xwl_fixes_selection_notify, NULL);
    E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SELECTION_NOTIFY, 
_xwl_selection_notify, NULL);
+   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SELECTION_REQUEST, 
_xwl_selection_request, NULL);
+   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY, 
_xwl_property, NULL);
    xconvertselection = dlsym(NULL, "XConvertSelection");
    string_atom = ecore_x_atom_get("UTF8_STRING");
+   timestamp_atom = ecore_x_atom_get("TIMESTAMP");
+   int_atom = ecore_x_atom_get("INTEGER");
+   incr_atom = ecore_x_atom_get("TIMESTAMP");
    xwl_dnd_atom = ecore_x_atom_get("E_XWL_DND_ATOM_HAHA");
+   pipes = eina_hash_int32_new((Eina_Free_Cb)_pipe_free);
    e_comp_shape_queue();
 }
 
@@ -206,4 +373,5 @@ EINTERN void
 dnd_shutdown(void)
 {
    E_FREE_LIST(handlers, ecore_event_handler_del);
+   E_FREE_FUNC(pipes, eina_hash_free);
 }

-- 


Reply via email to