Browse Source

Implement INCR transfers in the clipboard.

Christoph Lohmann 9 years ago
parent
commit
f8c6e7d041
1 changed files with 68 additions and 6 deletions
  1. 68 6
      st.c

+ 68 - 6
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