summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Zaoui <daniel.zaoui@yahoo.com>2015-04-18 21:44:35 +0300
committerDaniel Zaoui <daniel.zaoui@samsung.com>2015-05-07 13:46:31 +0300
commita290b6f07da30b503d6d52c840aea46d9a08fac6 (patch)
tree9787c903822f0565e284c6c6c913e85e47c41e62
parent7a49d23f90f41c478db9b7beb9763aa0cd74ae46 (diff)
downloadefl-devs/jackdanielz/dnd.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.c76
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_window_prop.c19
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);