[dev] [st] Better selection support?

From: Petr Sabata <psabata_AT_redhat.com>
Date: Mon, 4 Apr 2011 19:09:25 +0200

Unfortunatelly, many X applications aren't compatible with just UTF8_STRING,
so we'll have to do a little more. The patch below checks COMPOUND_TEXT,
UTF8_STRING and XA_STRING targets. It makes it more complicated and possibly
ugly, but it works...

It would be nice to respond with all three supported types to TARGETS,
I suppose. I'm not sure how to do that correctly, though.

-- Petr

---
 st.c |   75 ++++++++++++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/st.c b/st.c
index a6fb766..61b53b0 100644
--- a/st.c
+++ b/st.c
@@ -41,6 +41,11 @@
 #define DRAW_BUF_SIZ  1024
 #define UTF_SIZ       4
 
+/* Selection requests */
+#define REQ_CTEXT 1
+#define REQ_USTR  2
+#define REQ_STR   3
+
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -145,6 +150,12 @@ typedef struct {
 	} font, bfont;
 } DC;
 
+typedef struct {
+	Atom ctext;
+	Atom ustr;
+	Atom str;
+} SelectionTargets;
+
 /* TODO: use better name for vars... */
 typedef struct {
 	int mode;
@@ -152,7 +163,8 @@ typedef struct {
 	int ex, ey;
 	struct {int x, y;}  b, e;
 	char *clip;
-	Atom xtarget;
+	SelectionTargets tgt;
+	Atom deftgt;
 } Selection;
 
 #include "config.h"
@@ -219,7 +231,7 @@ static void selrequest(XEvent *);
 static void selinit(void);
 static inline int selected(int, int);
 static void selcopy(void);
-static void selpaste(void);
+static void selpaste(Atom);
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -371,9 +383,10 @@ selinit(void) {
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
-	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
-	if(sel.xtarget == None)
-		sel.xtarget = XA_STRING;
+	sel.tgt.ctext = XInternAtom(xw.dpy, "COMPOUND_TEXT", 0);
+	sel.tgt.ustr = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+	sel.tgt.str = XA_STRING;
+	sel.deftgt = sel.tgt.ctext;
 }
 
 static inline int 
@@ -439,25 +452,35 @@ selnotify(XEvent *e) {
 	int format;
 	unsigned char *data;
 	Atom type;
-
-	ofs = 0;
-	do {
-		if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
-					False, AnyPropertyType, &type, &format,
-					&nitems, &rem, &data)) {
-			fprintf(stderr, "Clipboard allocation failed\n");
-			return;
-		}
-		ttywrite((const char *) data, nitems * format / 8);
-		XFree(data);
-		/* number of 32-bit chunks returned */
-		ofs += nitems * format / 32;
-	} while(rem > 0);
+	static int req = REQ_CTEXT;
+
+	if (req == REQ_CTEXT && (*e).xselection.property == None) {
+		selpaste(sel.tgt.ustr);
+		req = REQ_USTR;
+	} else if (req == REQ_USTR && (*e).xselection.property == None) {
+		selpaste(sel.tgt.str);
+		req = REQ_STR;
+	} else {
+		ofs = 0;
+		do {
+			if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
+						False, AnyPropertyType, &type, &format,
+						&nitems, &rem, &data)) {
+				fprintf(stderr, "Clipboard allocation failed\n");
+				return;
+			}
+			ttywrite((const char *) data, nitems * format / 8);
+			XFree(data);
+			/* number of 32-bit chunks returned */
+			ofs += nitems * format / 32;
+		} while(rem > 0);
+		req = REQ_CTEXT;
+	}
 }
 
 void
-selpaste() {
-	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
+selpaste(Atom target) {
+	XConvertSelection(xw.dpy, XA_PRIMARY, target, XA_PRIMARY, xw.win, CurrentTime);
 }
 
 void
@@ -478,12 +501,14 @@ selrequest(XEvent *e) {
 	xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
 	if(xsre->target == xa_targets) {
 		/* respond with the supported type */
-		Atom string = sel.xtarget;
+		Atom string = sel.deftgt;
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				XA_ATOM, 32, PropModeReplace,
 				(unsigned char *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == sel.xtarget) {
+	} else if(xsre->target == sel.tgt.ctext ||
+	          xsre->target == sel.tgt.ustr ||
+	          xsre->target == sel.tgt.str) {
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				xsre->target, 8, PropModeReplace,
 				(unsigned char *) sel.clip, strlen(sel.clip));
@@ -520,7 +545,7 @@ brelease(XEvent *e) {
 	if(sel.bx==sel.ex && sel.by==sel.ey) {
 		sel.bx = -1;
 		if(b==2)
-			selpaste();
+			selpaste(sel.deftgt);
 	} else {
 		if(b==1)
 			selcopy();
@@ -1784,7 +1809,7 @@ kpress(XEvent *ev) {
 			break;
 		case XK_Insert:
 			if(shift)
-				selpaste();
+				selpaste(sel.deftgt);
 			break;
 		case XK_Return:
 			if(IS_SET(MODE_CRLF))
-- 
1.7.4
Received on Mon Apr 04 2011 - 19:09:25 CEST

This archive was generated by hypermail 2.2.0 : Mon Apr 04 2011 - 19:12:02 CEST