|
|
694158 |
From 7ed06a7b65c6f91da50b6664c742208ce520a983 Mon Sep 17 00:00:00 2001
|
|
|
694158 |
From: Albrecht Schlosser <albrechts.fltk@online.de>
|
|
|
694158 |
Date: Sat, 2 Jul 2022 16:08:20 +0200
|
|
|
694158 |
Subject: [PATCH] Improve X11 selection data transfer (INCR) protocol (issue
|
|
|
694158 |
451)
|
|
|
694158 |
|
|
|
694158 |
This improves reading large selections and fixes one more bug.
|
|
|
694158 |
|
|
|
694158 |
Backported from 'master' (fltk 1.4.0). For more information see
|
|
|
694158 |
commit c5556291624eec58ed9de186474dfcc858dca691,
|
|
|
694158 |
commit ef72df0dc7c3c48373c52085a855ac6ce6df4868 and issue 451
|
|
|
694158 |
https://github.com/fltk/fltk/issues/451
|
|
|
694158 |
---
|
|
|
694158 |
src/Fl_x.cxx | 64 ++++++++++++++++++++++++++++++++++++++++------------
|
|
|
694158 |
1 file changed, 49 insertions(+), 15 deletions(-)
|
|
|
694158 |
|
|
|
694158 |
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx
|
|
|
694158 |
index c8b9c06..a3ec6f2 100644
|
|
|
694158 |
--- a/src/Fl_x.cxx
|
|
|
694158 |
+++ b/src/Fl_x.cxx
|
|
|
694158 |
@@ -1275,13 +1275,25 @@ static bool getNextEvent(XEvent *event_return)
|
|
|
694158 |
|
|
|
694158 |
static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lower_bound) {
|
|
|
694158 |
// fprintf(stderr,"Incremental transfer starting due to INCR property\n");
|
|
|
694158 |
+ // fprintf(stderr, "[getIncrData:%d] lower_bound [in ] =%10ld\n", __LINE__, lower_bound);
|
|
|
694158 |
+ const size_t alloc_min = 4 * 1024 * 1024; // min. initial allocation
|
|
|
694158 |
+ const size_t alloc_max = 200 * 1024 * 1024; // max. initial allocation
|
|
|
694158 |
+ const size_t alloc_inc = 4 * 1024 * 1024; // (min.) increase if necessary
|
|
|
694158 |
size_t total = 0;
|
|
|
694158 |
+ size_t data_size = lower_bound + 1;
|
|
|
694158 |
+ if (data_size < alloc_min) {
|
|
|
694158 |
+ data_size = alloc_min;
|
|
|
694158 |
+ } else if (data_size > alloc_max) {
|
|
|
694158 |
+ data_size = alloc_max;
|
|
|
694158 |
+ }
|
|
|
694158 |
+ // fprintf(stderr, "[getIncrData:%d] initial alloc. =%10ld\n", __LINE__, data_size);
|
|
|
694158 |
+
|
|
|
694158 |
XEvent event;
|
|
|
694158 |
XDeleteProperty(fl_display, selevent.requestor, selevent.property);
|
|
|
694158 |
- data = (uchar*)realloc(data, lower_bound);
|
|
|
694158 |
+ data = (uchar*)realloc(data, data_size);
|
|
|
694158 |
if (!data) {
|
|
|
694158 |
- // fprintf(stderr, "[getIncrData:%d] realloc() FAILED, size = %ld\n", __LINE__, lower_bound);
|
|
|
694158 |
- Fl::fatal("Clipboard data transfer failed, size %ld too large.", lower_bound);
|
|
|
694158 |
+ // fprintf(stderr, "[getIncrData:%d] realloc() FAILED, size = %ld\n", __LINE__, data_size);
|
|
|
694158 |
+ Fl::fatal("Clipboard data transfer failed, size %ld is too large.", data_size);
|
|
|
694158 |
}
|
|
|
694158 |
for (;;) {
|
|
|
694158 |
if (!getNextEvent(&event)) {
|
|
|
694158 |
@@ -1297,20 +1309,24 @@ static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lo
|
|
|
694158 |
unsigned long bytes_after;
|
|
|
694158 |
unsigned char* prop = 0;
|
|
|
694158 |
long offset = 0;
|
|
|
694158 |
- size_t num_bytes;
|
|
|
694158 |
+ size_t num_bytes = 0;
|
|
|
694158 |
//size_t slice_size = 0;
|
|
|
694158 |
- do
|
|
|
694158 |
- {
|
|
|
694158 |
+ do {
|
|
|
694158 |
XGetWindowProperty(fl_display, selevent.requestor, selevent.property, offset, 70000, True,
|
|
|
694158 |
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
|
|
|
694158 |
num_bytes = nitems * (actual_format / 8);
|
|
|
694158 |
offset += num_bytes/4;
|
|
|
694158 |
// slice_size += num_bytes;
|
|
|
694158 |
- if (total + num_bytes > lower_bound) {
|
|
|
694158 |
- data = (uchar*)realloc(data, total + num_bytes);
|
|
|
694158 |
+ if (total + num_bytes + bytes_after + 1 > data_size) {
|
|
|
694158 |
+ data_size += alloc_inc;
|
|
|
694158 |
+ if (total + num_bytes + bytes_after + 1 > data_size)
|
|
|
694158 |
+ data_size = total + num_bytes + bytes_after + 1;
|
|
|
694158 |
+ // printf(" -- realloc(%9ld), total=%10ld, num_bytes=%7ld, bytes_after=%7ld (%7ld), required=%10ld\n",
|
|
|
694158 |
+ // data_size, total, num_bytes, bytes_after, num_bytes + bytes_after, total + num_bytes + bytes_after + 1);
|
|
|
694158 |
+ data = (uchar*)realloc(data, data_size);
|
|
|
694158 |
if (!data) {
|
|
|
694158 |
- // fprintf(stderr, "[getIncrData():%d] realloc() FAILED, size = %ld\n", __LINE__, total + num_bytes);
|
|
|
694158 |
- Fl::fatal("Clipboard data transfer failed, size %ld too large.", total + num_bytes);
|
|
|
694158 |
+ // fprintf(stderr, "[getIncrData():%d] realloc() FAILED, size = %ld\n", __LINE__, data_size);
|
|
|
694158 |
+ Fl::fatal("Clipboard data transfer failed, size %ld is too large.", data_size);
|
|
|
694158 |
}
|
|
|
694158 |
}
|
|
|
694158 |
memcpy(data + total, prop, num_bytes);
|
|
|
694158 |
@@ -1340,6 +1356,7 @@ static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lo
|
|
|
694158 |
}
|
|
|
694158 |
}
|
|
|
694158 |
XDeleteProperty(fl_display, selevent.requestor, selevent.property);
|
|
|
694158 |
+ // fprintf(stderr, "[getIncrData:%d] total data [out] =%10ld\n", __LINE__, (long)total);
|
|
|
694158 |
return (long)total;
|
|
|
694158 |
}
|
|
|
694158 |
|
|
|
694158 |
@@ -1488,20 +1505,37 @@ fprintf(stderr,"\n");*/
|
|
|
694158 |
return true;
|
|
|
694158 |
}
|
|
|
694158 |
if (actual == fl_INCR) {
|
|
|
694158 |
- // an X11 "integer" (32 bit), the "lower bound" of the clipboard size (see ICCCM)
|
|
|
694158 |
- size_t lower_bound = (*(unsigned long *)portion) & 0xFFFFFFFF;
|
|
|
694158 |
- // fprintf(stderr, "[fl_handle:%d] INCR: lower_bound = %ld\n", __LINE__, lower_bound);
|
|
|
694158 |
+ // From ICCCM: "The contents of the INCR property will be an integer, which
|
|
|
694158 |
+ // represents a lower bound on the number of bytes of data in the selection."
|
|
|
694158 |
+ //
|
|
|
694158 |
+ // However, some X clients don't set the integer ("lower bound") in the INCR
|
|
|
694158 |
+ // property, hence 'count' below is zero and we must not access '*portion'.
|
|
|
694158 |
+ // Debug:
|
|
|
694158 |
+#if (0)
|
|
|
694158 |
+ fprintf(stderr,
|
|
|
694158 |
+ "[fl_handle(SelectionNotify/INCR):%d] actual=%ld (INCR), format=%d, count=%ld, remaining=%ld",
|
|
|
694158 |
+ __LINE__, actual, format, count, remaining);
|
|
|
694158 |
+ if (portion && count > 0) {
|
|
|
694158 |
+ fprintf(stderr,
|
|
|
694158 |
+ ", portion=%p (%ld)", portion, *(long*)portion);
|
|
|
694158 |
+ }
|
|
|
694158 |
+ fprintf(stderr, "\n");
|
|
|
694158 |
+#endif
|
|
|
694158 |
+ size_t lower_bound = 0;
|
|
|
694158 |
+ if (portion && count > 0) {
|
|
|
694158 |
+ lower_bound = *(unsigned long *)portion;
|
|
|
694158 |
+ }
|
|
|
694158 |
bytesread = getIncrData(sn_buffer, xevent.xselection, lower_bound);
|
|
|
694158 |
XFree(portion);
|
|
|
694158 |
break;
|
|
|
694158 |
}
|
|
|
694158 |
// Make sure we got something sane...
|
|
|
694158 |
if ((portion == NULL) || (format != 8) || (count == 0)) {
|
|
|
694158 |
- if (portion) { XFree(portion); portion = 0; }
|
|
|
694158 |
+ if (portion) XFree(portion);
|
|
|
694158 |
return true;
|
|
|
694158 |
}
|
|
|
694158 |
sn_buffer = (unsigned char*)realloc(sn_buffer, bytesread+count+remaining+1);
|
|
|
694158 |
- memcpy(sn_buffer+bytesread, portion, count);
|
|
|
694158 |
+ memcpy(sn_buffer + bytesread, portion, count);
|
|
|
694158 |
if (portion) { XFree(portion); portion = 0; }
|
|
|
694158 |
bytesread += count;
|
|
|
694158 |
// Cannot trust data to be null terminated
|