diff options
author | Daniel Zaoui <daniel.zaoui@yahoo.com> | 2015-04-18 21:44:35 +0300 |
---|---|---|
committer | Daniel Zaoui <daniel.zaoui@samsung.com> | 2015-05-07 13:46:31 +0300 |
commit | a290b6f07da30b503d6d52c840aea46d9a08fac6 (patch) | |
tree | 9787c903822f0565e284c6c6c913e85e47c41e62 | |
parent | 7a49d23f90f41c478db9b7beb9763aa0cd74ae46 (diff) | |
download | efl-a290b6f07da30b503d6d52c840aea46d9a08fac6.tar.gz |
XDnD: support large images retrieval.devs/jackdanielz/dnd
Large images require a special process during pasting, as the data
is sent in chunks and not in only one part. The INCR mechanism
(ICCCM 2.7.2) is needed for this.
@feature
-rw-r--r-- | src/lib/ecore_x/xlib/ecore_x_events.c | 76 | ||||
-rw-r--r-- | src/lib/ecore_x/xlib/ecore_x_window_prop.c | 19 |
2 files changed, 90 insertions, 5 deletions
diff --git a/src/lib/ecore_x/xlib/ecore_x_events.c b/src/lib/ecore_x/xlib/ecore_x_events.c index 8ab79a4582..28df7fc0d5 100644 --- a/src/lib/ecore_x/xlib/ecore_x_events.c +++ b/src/lib/ecore_x/xlib/ecore_x_events.c @@ -22,6 +22,11 @@ #define CODESET "INVALID" #endif /* ifndef CODESET */ +static unsigned long _clipboard_incr_data_length = 0; /* Current received data length */ +static char *_clipboard_incr_data = NULL; /* Current received data */ +static Ecore_X_Event_Selection_Notify *_clipboard_incr_event = NULL; /* Event to send once the data is ready */ +Eina_Bool clipboard_incr_start = EINA_FALSE; + typedef struct _Ecore_X_Mouse_Down_Info { EINA_INLIST; @@ -1328,6 +1333,56 @@ _ecore_x_event_handle_circulate_request(XEvent *xevent) void _ecore_x_event_handle_property_notify(XEvent *xevent) { + /* ICCCM 2.7.2: incremental data sending + * The process has been initiated during selection_notify + * event (specifically in ecore_x_window_prop_property_get). + * This code retrieves the data from the owner and appends + * it to a buffer. + * A property returning a size equal to zero indicates the end + * of the sending and results in sending the event to the upper + * layer with all the data. + */ + if (xevent->xproperty.state == PropertyNewValue && clipboard_incr_start) + { + Atom type_ret = 0; + int size_ret = 0; + unsigned long num_ret = 0, bytes = 0, dummy; + unsigned char *prop_ret = NULL; + XGetWindowProperty(_ecore_x_disp, xevent->xproperty.window, + xevent->xproperty.atom, 0, 0, False, AnyPropertyType, + &type_ret, &size_ret, &num_ret, &bytes, &prop_ret); + XFree(prop_ret); + if (bytes <= 0) + { + if (_clipboard_incr_data_length) + { + /* The transaction is now finished. Th selection notify event can be sent + * with all the retrieved data. */ + _clipboard_incr_event->data = _ecore_x_selection_parse(_clipboard_incr_event->target, + _clipboard_incr_data, _clipboard_incr_data_length, size_ret); + _clipboard_incr_data = NULL; + _clipboard_incr_data_length = 0; + clipboard_incr_start = EINA_FALSE; + + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, _clipboard_incr_event, + _ecore_x_event_free_selection_notify, NULL); + ecore_x_window_prop_property_del(xevent->xproperty.window, xevent->xproperty.atom); + } + return; + } + /* Retrieval of the chunk */ + XGetWindowProperty(_ecore_x_disp, xevent->xproperty.window, + xevent->xproperty.atom, 0, bytes, False, AnyPropertyType, + &type_ret, &size_ret, &num_ret, &dummy, &prop_ret); + bytes = num_ret * size_ret / 8; + _clipboard_incr_data = realloc(_clipboard_incr_data, _clipboard_incr_data_length + bytes); + memcpy(_clipboard_incr_data + _clipboard_incr_data_length, prop_ret, bytes); + XFree(prop_ret); + _clipboard_incr_data_length += bytes; + /* We delete the property to indicate the owner to send the next chunk */ + ecore_x_window_prop_property_del(xevent->xproperty.window, xevent->xproperty.atom); + return; + } _ecore_x_last_event_mouse_move = 0; { Ecore_X_Event_Window_Property *e; @@ -1465,7 +1520,10 @@ _ecore_x_event_handle_selection_notify(XEvent *xevent) format = ecore_x_window_prop_property_get(xevent->xselection.requestor, xevent->xselection.property, XA_ATOM, 32, &data, &num_ret); - if (!format) + /* clipboard_incr_start is checked here because INCR requests are + * handled asynchronously. Most of the handling is in the property + * notify event handler. */ + if (!clipboard_incr_start && !format) { /* fallback if targets handling is not working and try get the * selection directly */ @@ -1484,7 +1542,7 @@ _ecore_x_event_handle_selection_notify(XEvent *xevent) xevent->xselection.property, AnyPropertyType, 8, &data, &num_ret); - if (!format) return; + if (!clipboard_incr_start && !format) return; } e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify)); @@ -1510,10 +1568,18 @@ _ecore_x_event_handle_selection_notify(XEvent *xevent) else e->selection = ECORE_X_SELECTION_OTHER; - e->data = _ecore_x_selection_parse(e->target, data, num_ret, format); + if (!clipboard_incr_start) + { + e->data = _ecore_x_selection_parse(e->target, data, num_ret, format); - ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, - _ecore_x_event_free_selection_notify, NULL); + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, + _ecore_x_event_free_selection_notify, NULL); + } + else + { + /* In case of INCR, the event is stored until the data is ready */ + _clipboard_incr_event = e; + } } void diff --git a/src/lib/ecore_x/xlib/ecore_x_window_prop.c b/src/lib/ecore_x/xlib/ecore_x_window_prop.c index 151f65a8bc..b66107f262 100644 --- a/src/lib/ecore_x/xlib/ecore_x_window_prop.c +++ b/src/lib/ecore_x/xlib/ecore_x_window_prop.c @@ -16,6 +16,8 @@ XChangeProperty(_ecore_x_disp, win, atom, XA_CARDINAL, 32, PropModeReplace, \ (unsigned char *)p_val, cnt) +extern Eina_Bool clipboard_incr_start; + /* * Set CARD32 (array) property */ @@ -545,6 +547,23 @@ ecore_x_window_prop_property_get(Ecore_X_Window win, if (_ecore_xlib_sync) ecore_x_sync(); if (ret != Success) return 0; + if (type_ret != type) + { + /* In case of INCR (ICCCM 2.7.2), we have to delete + * the property to request the owner to send the data + * chunks. + * This part of code needs to be in this function, as + * type_ret is not returned so not known by the caller. + */ + char *atom_name = ecore_x_atom_name_get(type_ret); + if (atom_name && !strcmp(atom_name, "INCR")) + { + clipboard_incr_start = EINA_TRUE; + ecore_x_window_prop_property_del(win, property); + num_ret = 0; /* Forcing early exit */ + } + free(atom_name); + } if ((!num_ret) || (size_ret <= 0)) { XFree(prop_ret); |