summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Zaoui <daniel.zaoui@yahoo.com>2016-11-14 09:17:10 +0200
committerDaniel Zaoui <daniel.zaoui@yahoo.com>2016-11-14 09:17:10 +0200
commit66bf177884b8128dea75483ce5f4b633f81b6df6 (patch)
tree388c06135f76b76b21e71a03a3b16e13aa03e1ef
parent819c14c86ff29ac62354e5a92a26779c0cbe6236 (diff)
downloadefl-66bf177884b8128dea75483ce5f4b633f81b6df6.tar.gz
TEMP 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. Currently: seems stable, doesn't block Still todo: - after a lot of one shot pastes, takes time to come back to stability - sometimes receives UTF8_STRING from firefox. why? @feature
-rw-r--r--src/lib/ecore_x/ecore_x_events.c112
-rw-r--r--src/lib/ecore_x/ecore_x_window_prop.c18
2 files changed, 124 insertions, 6 deletions
diff --git a/src/lib/ecore_x/ecore_x_events.c b/src/lib/ecore_x/ecore_x_events.c
index 0049fca25d..10c7b431f0 100644
--- a/src/lib/ecore_x/ecore_x_events.c
+++ b/src/lib/ecore_x/ecore_x_events.c
@@ -22,6 +22,14 @@
#define CODESET "INVALID"
#endif /* ifndef CODESET */
+/* INCR mechanism variables */
+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;
+static Atom _clipboard_data_atom;
+static unsigned long _clipboard_incr_data_expected_length = 0;
+
typedef struct _Ecore_X_Mouse_Down_Info
{
EINA_INLIST;
@@ -179,7 +187,7 @@ _ecore_x_event_free_selection_notify(void *data EINA_UNUSED,
e = ev;
sel = e->data;
- if (sel->free)
+ if (sel && sel->free)
sel->free(sel);
free(e->target);
@@ -1362,6 +1370,69 @@ _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 (type_ret == _clipboard_data_atom)
+ {
+ printf("%s/%d: Type %s == %s\n", __FUNCTION__, __LINE__, ecore_x_atom_name_get(type_ret), ecore_x_atom_name_get(_clipboard_data_atom));
+ if (bytes <= 0)
+ {
+ printf("Sizes: %d - %d\n", _clipboard_incr_data_length, _clipboard_incr_data_expected_length);
+ if (_clipboard_incr_data_length == _clipboard_incr_data_expected_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);
+
+ 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);
+ printf("%s/%d: End of image (%d)\n", __FUNCTION__, __LINE__, _clipboard_incr_data_length);
+ }
+ else
+ {
+ free(_clipboard_incr_data);
+ _ecore_x_event_free_selection_notify(NULL, _clipboard_incr_event);
+ }
+ _clipboard_incr_start = EINA_FALSE;
+ _clipboard_incr_data = NULL;
+ _clipboard_incr_data_length = 0;
+ _clipboard_incr_event = NULL;
+ 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);
+ printf("%s/%d: Data %.8X\n", __FUNCTION__, __LINE__, *(unsigned int *)prop_ret);
+ 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;
@@ -1491,11 +1562,15 @@ _ecore_x_event_handle_selection_notify(XEvent *xevent)
unsigned char *data = NULL;
Ecore_X_Atom selection;
int num_ret, format;
+ Eina_Bool incr_already_started = _clipboard_incr_start;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
_ecore_x_last_event_mouse_move = 0;
selection = xevent->xselection.selection;
+ printf("%s/%d: Target %s (%sINCR)\n", __FUNCTION__, __LINE__, ecore_x_atom_name_get(xevent->xselection.target),
+ _clipboard_incr_start?"":"No ");
+ _clipboard_incr_start = EINA_FALSE;
if (xevent->xselection.target == ECORE_X_ATOM_SELECTION_TARGETS)
{
format = ecore_x_window_prop_property_get(xevent->xselection.requestor,
@@ -1520,9 +1595,21 @@ _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;
}
+ printf("%s/%d: NEW_INCR: %s CURR_INCR: %s\n", __FUNCTION__, __LINE__,
+ _clipboard_incr_start?"Yes":"No ",
+ incr_already_started?"Yes":"No");
+ if (_clipboard_incr_start && incr_already_started)
+ {
+ /* We don't do anything if another INCR request is received when one
+ * is already under process */
+ if (data) free(data);
+ return;
+ }
+ _clipboard_incr_start = _clipboard_incr_start ^ incr_already_started;
+
e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify));
if (!e)
{
@@ -1547,10 +1634,23 @@ _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);
-
- ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e,
- _ecore_x_event_free_selection_notify, NULL);
+ 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);
+ }
+ else
+ {
+ /* In case of INCR, the event is stored until the data is ready */
+ if (_clipboard_incr_event) _ecore_x_event_free_selection_notify(NULL, _clipboard_incr_event);
+ _clipboard_incr_data_expected_length = *(int *)data;
+ printf("%s/%d: Target %s Size %d\n", __FUNCTION__, __LINE__, e->target, _clipboard_incr_data_expected_length);
+ _clipboard_incr_event = e;
+ _clipboard_data_atom = xevent->xselection.target;
+ ecore_x_window_prop_property_del(xevent->xselection.requestor, xevent->xselection.property);
+ free(data);
+ }
}
void
diff --git a/src/lib/ecore_x/ecore_x_window_prop.c b/src/lib/ecore_x/ecore_x_window_prop.c
index 043e50e391..39a1215bb3 100644
--- a/src/lib/ecore_x/ecore_x_window_prop.c
+++ b/src/lib/ecore_x/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
*/
@@ -555,6 +557,21 @@ 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.
+ * Data is retrieved by the function _ecore_x_event_handle_property_notify.
+ * This part of code needs to be in this function, as
+ * this is the highest layer knowing of the type_ret,
+ * needed to identify the INCR request.
+ */
+ char *atom_name = ecore_x_atom_name_get(type_ret);
+ printf("%s/%d: type %s\n", __FUNCTION__, __LINE__, atom_name);
+ _clipboard_incr_start = (atom_name && !strcmp(atom_name, "INCR"));
+ free(atom_name);
+ }
if ((!num_ret) || (size_ret <= 0))
{
XFree(prop_ret);
@@ -583,6 +600,7 @@ ecore_x_window_prop_property_get(Ecore_X_Window win,
((unsigned int *)*data)[i] = ((unsigned long *)prop_ret)[i];
break;
}
+ printf("Data %s\n", *data);
XFree(prop_ret);