From f8c6e7d0419d10c1425cb2c7123c5798ffb3b942 Mon Sep 17 00:00:00 2001 From: Christoph Lohmann <20h@r-36.net> Date: Fri, 10 Jul 2015 14:10:17 +0200 Subject: [PATCH] Implement INCR transfers in the clipboard. --- st.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/st.c b/st.c index 274ac5d..17e0a65 100644 --- a/st.c +++ b/st.c @@ -452,6 +452,7 @@ static void focus(XEvent *); static void brelease(XEvent *); static void bpress(XEvent *); static void bmotion(XEvent *); +static void propnotify(XEvent *); static void selnotify(XEvent *); static void selclear(XEvent *); static void selrequest(XEvent *); @@ -500,6 +501,11 @@ static void (*handler[LASTEvent])(XEvent *) = { */ /* [SelectionClear] = selclear, */ [SelectionNotify] = selnotify, +/* + * PropertyNotify is only turned on when there is some INCR transfer happening + * for the selection retrieval. + */ + [PropertyNotify] = propnotify, [SelectionRequest] = selrequest, }; @@ -1028,21 +1034,41 @@ selcopy(Time 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 selnotify(XEvent *e) { ulong nitems, ofs, rem; int format; uchar *data, *last, *repl; - Atom type; - XSelectionEvent *xsev; + Atom type, incratom, property; ofs = 0; - xsev = &e->xselection; - if (xsev->property == None) - return; + if (e->type == SelectionNotify) { + property = e->xselection.property; + } else if(e->type == PropertyNotify) { + property = e->xproperty.atom; + } else { + return; + } + if (property == None) + return; + do { - if (XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs, + if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, BUFSIZ/4, False, AnyPropertyType, &type, &format, &nitems, &rem, &data)) { @@ -1050,6 +1076,35 @@ selnotify(XEvent *e) 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: * Line endings are inconsistent in the terminal and GUI world @@ -1072,6 +1127,13 @@ selnotify(XEvent *e) /* number of 32-bit chunks returned */ ofs += nitems * format / 32; } 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