Implement INCR transfers in the clipboard.

dev
Christoph Lohmann 2015-07-10 14:10:17 +02:00
parent 539afe3af1
commit f8c6e7d041
1 changed files with 68 additions and 6 deletions

74
st.c
View File

@ -452,6 +452,7 @@ static void focus(XEvent *);
static void brelease(XEvent *); static void brelease(XEvent *);
static void bpress(XEvent *); static void bpress(XEvent *);
static void bmotion(XEvent *); static void bmotion(XEvent *);
static void propnotify(XEvent *);
static void selnotify(XEvent *); static void selnotify(XEvent *);
static void selclear(XEvent *); static void selclear(XEvent *);
static void selrequest(XEvent *); static void selrequest(XEvent *);
@ -500,6 +501,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
*/ */
/* [SelectionClear] = selclear, */ /* [SelectionClear] = selclear, */
[SelectionNotify] = selnotify, [SelectionNotify] = selnotify,
/*
* PropertyNotify is only turned on when there is some INCR transfer happening
* for the selection retrieval.
*/
[PropertyNotify] = propnotify,
[SelectionRequest] = selrequest, [SelectionRequest] = selrequest,
}; };
@ -1028,21 +1034,41 @@ selcopy(Time t)
xsetsel(getsel(), t); xsetsel(getsel(), t);
} }
void
propnotify(XEvent *e)
{
XPropertyEvent *xpev;
Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
xpev = &e->xproperty;
if (xpev->state == PropertyNewValue &&
(xpev->atom == XA_PRIMARY ||
xpev->atom == clipboard)) {
slenotify(e);
}
}
void void
selnotify(XEvent *e) selnotify(XEvent *e)
{ {
ulong nitems, ofs, rem; ulong nitems, ofs, rem;
int format; int format;
uchar *data, *last, *repl; uchar *data, *last, *repl;
Atom type; Atom type, incratom, property;
XSelectionEvent *xsev;
ofs = 0; ofs = 0;
xsev = &e->xselection; if (e->type == SelectionNotify) {
if (xsev->property == None) property = e->xselection.property;
return; } else if(e->type == PropertyNotify) {
property = e->xproperty.atom;
} else {
return;
}
if (property == None)
return;
do { do {
if (XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs, if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
BUFSIZ/4, False, AnyPropertyType, BUFSIZ/4, False, AnyPropertyType,
&type, &format, &nitems, &rem, &type, &format, &nitems, &rem,
&data)) { &data)) {
@ -1050,6 +1076,35 @@ selnotify(XEvent *e)
return; return;
} }
if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
/*
* If there is some PropertyNotify with no data, then
* this is the signal of the selection owner that all
* data has been transferred. We won't need to receive
* PropertyNotify events anymore.
*/
MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
&xw.attrs);
}
if (type == incratom) {
/*
* Activate the PropertyNotify events so we receive
* when the selection owner does send us the next
* chunk of data.
*/
MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
&xw.attrs);
/*
* Deleting the property is the transfer start signal.
*/
XDeleteProperty(xw.dpy, xw.win, (int)property);
continue;
}
/* /*
* As seen in getsel: * As seen in getsel:
* Line endings are inconsistent in the terminal and GUI world * Line endings are inconsistent in the terminal and GUI world
@ -1072,6 +1127,13 @@ selnotify(XEvent *e)
/* number of 32-bit chunks returned */ /* number of 32-bit chunks returned */
ofs += nitems * format / 32; ofs += nitems * format / 32;
} while (rem > 0); } while (rem > 0);
/*
* Deleting the property again tells the selection owner to send the
* next data chunk in the property.
*/
if (e->type == PropertyNotify)
XDeleteProperty(xw.dpy, xw.win, (int)property);
} }
void void