sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

st-drag-n-drop-0.9.2.diff (9102B)


      1 diff --git a/config.def.h b/config.def.h
      2 index 2cd740a..3045d0a 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -93,6 +93,13 @@ char *termname = "st-256color";
      6   */
      7  unsigned int tabspaces = 8;
      8  
      9 +/*
     10 + * drag and drop escape characters
     11 + *
     12 + * this will add a '\' before any characters specified in the string.
     13 + */
     14 +char *xdndescchar = " !\"#$&'()*;<>?[\\]^`{|}~";
     15 +
     16  /* Terminal colors (16 first used in escape sequence) */
     17  static const char *colorname[] = {
     18  	/* 8 normal colors */
     19 diff --git a/st.h b/st.h
     20 index fd3b0d8..62c7405 100644
     21 --- a/st.h
     22 +++ b/st.h
     23 @@ -20,6 +20,10 @@
     24  #define TRUECOLOR(r,g,b)	(1 << 24 | (r) << 16 | (g) << 8 | (b))
     25  #define IS_TRUECOL(x)		(1 << 24 & (x))
     26  
     27 +#define HEX_TO_INT(c)		((c) >= '0' && (c) <= '9' ? (c) - '0' : \
     28 +				(c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
     29 +				(c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : -1)
     30 +
     31  enum glyph_attribute {
     32  	ATTR_NULL       = 0,
     33  	ATTR_BOLD       = 1 << 0,
     34 diff --git a/x.c b/x.c
     35 index d73152b..1c4b9aa 100644
     36 --- a/x.c
     37 +++ b/x.c
     38 @@ -94,6 +94,12 @@ typedef struct {
     39  	Drawable buf;
     40  	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
     41  	Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
     42 +	Atom XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus,
     43 +	     XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove,
     44 +	     XdndActionLink, XdndActionAsk, XdndActionPrivate, XtextUriList,
     45 +	     XtextPlain, XdndAware;
     46 +	int64_t XdndSourceWin, XdndSourceVersion;
     47 +	int32_t XdndSourceFormat;
     48  	struct {
     49  		XIM xim;
     50  		XIC xic;
     51 @@ -169,6 +175,9 @@ static void visibility(XEvent *);
     52  static void unmap(XEvent *);
     53  static void kpress(XEvent *);
     54  static void cmessage(XEvent *);
     55 +static void xdndenter(XEvent *);
     56 +static void xdndpos(XEvent *);
     57 +static void xdnddrop(XEvent *);
     58  static void resize(XEvent *);
     59  static void focus(XEvent *);
     60  static uint buttonmask(uint);
     61 @@ -178,6 +187,8 @@ static void bpress(XEvent *);
     62  static void bmotion(XEvent *);
     63  static void propnotify(XEvent *);
     64  static void selnotify(XEvent *);
     65 +static void xdndsel(XEvent *);
     66 +static void xdndpastedata(char *);
     67  static void selclear_(XEvent *);
     68  static void selrequest(XEvent *);
     69  static void setsel(char *, Time);
     70 @@ -220,6 +231,7 @@ static DC dc;
     71  static XWindow xw;
     72  static XSelection xsel;
     73  static TermWindow win;
     74 +const char XdndVersion = 5;
     75  
     76  /* Font Ring Cache */
     77  enum {
     78 @@ -536,6 +548,11 @@ selnotify(XEvent *e)
     79  	if (property == None)
     80  		return;
     81  
     82 +	if (property == xw.XdndSelection) {
     83 +		xdndsel(e);
     84 +		return;
     85 +	}
     86 +
     87  	do {
     88  		if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
     89  					BUFSIZ/4, False, AnyPropertyType,
     90 @@ -604,6 +621,95 @@ selnotify(XEvent *e)
     91  	XDeleteProperty(xw.dpy, xw.win, (int)property);
     92  }
     93  
     94 +void
     95 +xdndsel(XEvent *e)
     96 +{
     97 +	char* data;
     98 +	unsigned long result;
     99 +
    100 +	Atom actualType;
    101 +	int32_t actualFormat;
    102 +	unsigned long bytesAfter;
    103 +	XEvent reply = { ClientMessage };
    104 +
    105 +	reply.xclient.window = xw.XdndSourceWin;
    106 +	reply.xclient.format = 32;
    107 +	reply.xclient.data.l[0] = (long) xw.win;
    108 +	reply.xclient.data.l[2] = 0;
    109 +	reply.xclient.data.l[3] = 0;
    110 +
    111 +	XGetWindowProperty((Display*) xw.dpy, e->xselection.requestor,
    112 +			e->xselection.property, 0, LONG_MAX, False,
    113 +			e->xselection.target, &actualType, &actualFormat, &result,
    114 +			&bytesAfter, (unsigned char**) &data);
    115 +
    116 +	if (result == 0)
    117 +		return;
    118 +
    119 +	if (data) {
    120 +		xdndpastedata(data);
    121 +		XFree(data);
    122 +	}
    123 +
    124 +	if (xw.XdndSourceVersion >= 2) {
    125 +		reply.xclient.message_type = xw.XdndFinished;
    126 +		reply.xclient.data.l[1] = result;
    127 +		reply.xclient.data.l[2] = xw.XdndActionCopy;
    128 +
    129 +		XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask,
    130 +			 	&reply);
    131 +		XFlush((Display*) xw.dpy);
    132 +	}
    133 +}
    134 +
    135 +int
    136 +xdndurldecode(char *src, char *dest)
    137 +{
    138 +	char c;
    139 +	int i = 0;
    140 +
    141 +	while (*src) {
    142 +		if (*src == '%' && HEX_TO_INT(src[1]) != -1 && HEX_TO_INT(src[2]) != -1) {
    143 +			/* handle %xx escape sequences in url e.g. %20 == ' ' */
    144 +			c = (char)((HEX_TO_INT(src[1]) << 4) | HEX_TO_INT(src[2]));
    145 +			src += 3;
    146 +		} else {
    147 +			c = *src++;
    148 +		}
    149 +		if (strchr(xdndescchar, c) != NULL) {
    150 +			*dest++ = '\\';
    151 +			i++;
    152 +		}
    153 +		*dest++ = c;
    154 +		i++;
    155 +	}
    156 +	*dest++ = ' ';
    157 +	*dest = '\0';
    158 +	return i + 1;
    159 +}
    160 +
    161 +void
    162 +xdndpastedata(char *data)
    163 +{
    164 +	char *pastedata, *t;
    165 +	int i = 0;
    166 +
    167 +	pastedata = (char *)malloc(strlen(data) * 2 + 1);
    168 +	*pastedata = '\0';
    169 +
    170 +	t = strtok(data, "\n\r");
    171 +	while(t != NULL) {
    172 +		/* remove 'file://' prefix if it exists */
    173 +		if (strncmp(data, "file://", 7) == 0)
    174 +			t += 7;
    175 +		i += xdndurldecode(t, pastedata + i);
    176 +		t = strtok(NULL, "\n\r");
    177 +	}
    178 +
    179 +	xsetsel(pastedata);
    180 +	selpaste(0);
    181 +}
    182 +
    183  void
    184  xclipcopy(void)
    185  {
    186 @@ -1227,6 +1333,26 @@ xinit(int cols, int rows)
    187  	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
    188  			PropModeReplace, (uchar *)&thispid, 1);
    189  
    190 +	/* Xdnd setup */
    191 +	xw.XdndTypeList = XInternAtom(xw.dpy, "XdndTypeList", 0);
    192 +	xw.XdndSelection = XInternAtom(xw.dpy, "XdndSelection", 0);
    193 +	xw.XdndEnter = XInternAtom(xw.dpy, "XdndEnter", 0);
    194 +	xw.XdndPosition = XInternAtom(xw.dpy, "XdndPosition", 0);
    195 +	xw.XdndStatus = XInternAtom(xw.dpy, "XdndStatus", 0);
    196 +	xw.XdndLeave = XInternAtom(xw.dpy, "XdndLeave", 0);
    197 +	xw.XdndDrop = XInternAtom(xw.dpy, "XdndDrop", 0);
    198 +	xw.XdndFinished = XInternAtom(xw.dpy, "XdndFinished", 0);
    199 +	xw.XdndActionCopy = XInternAtom(xw.dpy, "XdndActionCopy", 0);
    200 +	xw.XdndActionMove = XInternAtom(xw.dpy, "XdndActionMove", 0);
    201 +	xw.XdndActionLink = XInternAtom(xw.dpy, "XdndActionLink", 0);
    202 +	xw.XdndActionAsk = XInternAtom(xw.dpy, "XdndActionAsk", 0);
    203 +	xw.XdndActionPrivate = XInternAtom(xw.dpy, "XdndActionPrivate", 0);
    204 +	xw.XtextUriList = XInternAtom((Display*) xw.dpy, "text/uri-list", 0);
    205 +	xw.XtextPlain = XInternAtom((Display*) xw.dpy, "text/plain", 0);
    206 +	xw.XdndAware = XInternAtom(xw.dpy, "XdndAware", 0);
    207 +	XChangeProperty(xw.dpy, xw.win, xw.XdndAware, 4, 32, PropModeReplace,
    208 +			&XdndVersion, 1);
    209 +
    210  	win.mode = MODE_NUMLOCK;
    211  	resettitle();
    212  	xhints();
    213 @@ -1908,6 +2034,132 @@ cmessage(XEvent *e)
    214  	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
    215  		ttyhangup();
    216  		exit(0);
    217 +	} else if (e->xclient.message_type == xw.XdndEnter) {
    218 +		xw.XdndSourceWin = e->xclient.data.l[0];
    219 +		xw.XdndSourceVersion = e->xclient.data.l[1] >> 24;
    220 +		xw.XdndSourceFormat = None;
    221 +		if (xw.XdndSourceVersion > 5)
    222 +			return;
    223 +		xdndenter(e);
    224 +	} else if (e->xclient.message_type == xw.XdndPosition
    225 +			&& xw.XdndSourceVersion <= 5) {
    226 +		xdndpos(e);
    227 +	} else if (e->xclient.message_type == xw.XdndDrop
    228 +			&& xw.XdndSourceVersion <= 5) {
    229 +		xdnddrop(e);
    230 +	}
    231 +}
    232 +
    233 +void
    234 +xdndenter(XEvent *e)
    235 +{
    236 +	unsigned long count;
    237 +	Atom* formats;
    238 +	Atom real_formats[6];
    239 +	Bool list;
    240 +	Atom actualType;
    241 +	int32_t actualFormat;
    242 +	unsigned long bytesAfter;
    243 +	unsigned long i;
    244 +
    245 +	list = e->xclient.data.l[1] & 1;
    246 +
    247 +	if (list) {
    248 +		XGetWindowProperty((Display*) xw.dpy,
    249 +			xw.XdndSourceWin,
    250 +			xw.XdndTypeList,
    251 +			0,
    252 +			LONG_MAX,
    253 +			False,
    254 +			4,
    255 +			&actualType,
    256 +			&actualFormat,
    257 +			&count,
    258 +			&bytesAfter,
    259 +			(unsigned char**) &formats);
    260 +	} else {
    261 +		count = 0;
    262 +
    263 +		if (e->xclient.data.l[2] != None)
    264 +			real_formats[count++] = e->xclient.data.l[2];
    265 +		if (e->xclient.data.l[3] != None)
    266 +			real_formats[count++] = e->xclient.data.l[3];
    267 +		if (e->xclient.data.l[4] != None)
    268 +			real_formats[count++] = e->xclient.data.l[4];
    269 +
    270 +		formats = real_formats;
    271 +	}
    272 +
    273 +	for (i = 0; i < count; i++) {
    274 +		if (formats[i] == xw.XtextUriList || formats[i] == xw.XtextPlain) {
    275 +			xw.XdndSourceFormat = formats[i];
    276 +			break;
    277 +		}
    278 +	}
    279 +
    280 +	if (list)
    281 +		XFree(formats);
    282 +}
    283 +
    284 +void
    285 +xdndpos(XEvent *e)
    286 +{
    287 +	const int32_t xabs = (e->xclient.data.l[2] >> 16) & 0xffff;
    288 +	const int32_t yabs = (e->xclient.data.l[2]) & 0xffff;
    289 +	Window dummy;
    290 +	int32_t xpos, ypos;
    291 +	XEvent reply = { ClientMessage };
    292 +
    293 +	reply.xclient.window = xw.XdndSourceWin;
    294 +	reply.xclient.format = 32;
    295 +	reply.xclient.data.l[0] = (long) xw.win;
    296 +	reply.xclient.data.l[2] = 0;
    297 +	reply.xclient.data.l[3] = 0;
    298 +
    299 +	XTranslateCoordinates((Display*) xw.dpy,
    300 +		XDefaultRootWindow((Display*) xw.dpy),
    301 +		(Window) xw.win,
    302 +		xabs, yabs,
    303 +		&xpos, &ypos,
    304 +		&dummy);
    305 +
    306 +	reply.xclient.message_type = xw.XdndStatus;
    307 +
    308 +	if (xw.XdndSourceFormat) {
    309 +		reply.xclient.data.l[1] = 1;
    310 +		if (xw.XdndSourceVersion >= 2)
    311 +			reply.xclient.data.l[4] = xw.XdndActionCopy;
    312 +	}
    313 +
    314 +	XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask,
    315 +			&reply);
    316 +	XFlush((Display*) xw.dpy);
    317 +}
    318 +
    319 +void
    320 +xdnddrop(XEvent *e)
    321 +{
    322 +	Time time = CurrentTime;
    323 +	XEvent reply = { ClientMessage };
    324 +
    325 +	reply.xclient.window = xw.XdndSourceWin;
    326 +	reply.xclient.format = 32;
    327 +	reply.xclient.data.l[0] = (long) xw.win;
    328 +	reply.xclient.data.l[2] = 0;
    329 +	reply.xclient.data.l[3] = 0;
    330 +
    331 +	if (xw.XdndSourceFormat) {
    332 +		if (xw.XdndSourceVersion >= 1)
    333 +			time = e->xclient.data.l[2];
    334 +
    335 +		XConvertSelection((Display*) xw.dpy, xw.XdndSelection,
    336 +				xw.XdndSourceFormat, xw.XdndSelection, (Window) xw.win, time);
    337 +	} else if (xw.XdndSourceVersion >= 2) {
    338 +		reply.xclient.message_type = xw.XdndFinished;
    339 +
    340 +		XSendEvent((Display*) xw.dpy, xw.XdndSourceWin,
    341 +				False, NoEventMask, &reply);
    342 +		XFlush((Display*) xw.dpy);
    343  	}
    344  }
    345