+void write_data(Window requestor, Atom property, Atom type, int format,
+ void *vdata, size_t size)
+{
+ int bformat = format / 8; /* bytes per element */
+ unsigned char *data = (unsigned char *)vdata;
+ XEvent ev;
+
+ if (!use_outgoing_incr || size * bformat <= sel_delta) {
+ XChangeProperty(disp, requestor, property, type, format,
+ PropModeReplace, data, size);
+ } else {
+ /*
+ * For large data, an incremental transfer as per ICCCM 2.7.2.
+ */
+ Cardinal totalsize = size * bformat;
+ Cardinal sent, thissize;
+
+ /*
+ * We're going to need PropertyNotify events on the target
+ * window to tell us when to send the next chunk.
+ */
+ XSelectInput(disp, requestor, PropertyChangeMask);
+
+ /*
+ * Start by sending a single 32-bit word with type INCR giving
+ * the total size in bytes.
+ */
+ XChangeProperty(disp, requestor, property, incr_atom, 32,
+ PropModeReplace, (unsigned char *)&totalsize, 1);
+
+ /*
+ * Now set up an entry in our list of ongoing incremental
+ * transfers, so that whenever that property is deleted, we'll
+ * send the next batch.
+ */
+ if (nincrs >= incrsize) {
+ incrsize = nincrs * 9 / 8 + 16;
+ incrs = realloc(incrs, incrsize * sizeof(*incrs));
+ if (!incrs)
+ error ("out of memory");
+ }
+ incrs[nincrs].window = requestor;
+ incrs[nincrs].property = property;
+ incrs[nincrs].type = type;
+ incrs[nincrs].format = format;
+ incrs[nincrs].size = totalsize;
+ incrs[nincrs].data = malloc(totalsize);
+ if (!incrs[nincrs].data)
+ error("out of memory");
+ memcpy(incrs[nincrs].data, data, size);
+ nincrs++;
+ }
+}
+