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 (9044B)


      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..a152ea8 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,93 @@ 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 +		t += 7; /* remove 'file://' prefix */
    173 +		i += xdndurldecode(t, pastedata + i);
    174 +		t = strtok(NULL, "\n\r");
    175 +	}
    176 +
    177 +	xsetsel(pastedata);
    178 +	selpaste(0);
    179 +}
    180 +
    181  void
    182  xclipcopy(void)
    183  {
    184 @@ -1227,6 +1331,26 @@ xinit(int cols, int rows)
    185  	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
    186  			PropModeReplace, (uchar *)&thispid, 1);
    187  
    188 +	/* Xdnd setup */
    189 +	xw.XdndTypeList = XInternAtom(xw.dpy, "XdndTypeList", 0);
    190 +	xw.XdndSelection = XInternAtom(xw.dpy, "XdndSelection", 0);
    191 +	xw.XdndEnter = XInternAtom(xw.dpy, "XdndEnter", 0);
    192 +	xw.XdndPosition = XInternAtom(xw.dpy, "XdndPosition", 0);
    193 +	xw.XdndStatus = XInternAtom(xw.dpy, "XdndStatus", 0);
    194 +	xw.XdndLeave = XInternAtom(xw.dpy, "XdndLeave", 0);
    195 +	xw.XdndDrop = XInternAtom(xw.dpy, "XdndDrop", 0);
    196 +	xw.XdndFinished = XInternAtom(xw.dpy, "XdndFinished", 0);
    197 +	xw.XdndActionCopy = XInternAtom(xw.dpy, "XdndActionCopy", 0);
    198 +	xw.XdndActionMove = XInternAtom(xw.dpy, "XdndActionMove", 0);
    199 +	xw.XdndActionLink = XInternAtom(xw.dpy, "XdndActionLink", 0);
    200 +	xw.XdndActionAsk = XInternAtom(xw.dpy, "XdndActionAsk", 0);
    201 +	xw.XdndActionPrivate = XInternAtom(xw.dpy, "XdndActionPrivate", 0);
    202 +	xw.XtextUriList = XInternAtom((Display*) xw.dpy, "text/uri-list", 0);
    203 +	xw.XtextPlain = XInternAtom((Display*) xw.dpy, "text/plain", 0);
    204 +	xw.XdndAware = XInternAtom(xw.dpy, "XdndAware", 0);
    205 +	XChangeProperty(xw.dpy, xw.win, xw.XdndAware, 4, 32, PropModeReplace,
    206 +			&XdndVersion, 1);
    207 +
    208  	win.mode = MODE_NUMLOCK;
    209  	resettitle();
    210  	xhints();
    211 @@ -1908,6 +2032,132 @@ cmessage(XEvent *e)
    212  	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
    213  		ttyhangup();
    214  		exit(0);
    215 +	} else if (e->xclient.message_type == xw.XdndEnter) {
    216 +		xw.XdndSourceWin = e->xclient.data.l[0];
    217 +		xw.XdndSourceVersion = e->xclient.data.l[1] >> 24;
    218 +		xw.XdndSourceFormat = None;
    219 +		if (xw.XdndSourceVersion > 5)
    220 +			return;
    221 +		xdndenter(e);
    222 +	} else if (e->xclient.message_type == xw.XdndPosition
    223 +			&& xw.XdndSourceVersion <= 5) {
    224 +		xdndpos(e);
    225 +	} else if (e->xclient.message_type == xw.XdndDrop
    226 +			&& xw.XdndSourceVersion <= 5) {
    227 +		xdnddrop(e);
    228 +	}
    229 +}
    230 +
    231 +void
    232 +xdndenter(XEvent *e)
    233 +{
    234 +	unsigned long count;
    235 +	Atom* formats;
    236 +	Atom real_formats[6];
    237 +	Bool list;
    238 +	Atom actualType;
    239 +	int32_t actualFormat;
    240 +	unsigned long bytesAfter;
    241 +	unsigned long i;
    242 +
    243 +	list = e->xclient.data.l[1] & 1;
    244 +
    245 +	if (list) {
    246 +		XGetWindowProperty((Display*) xw.dpy,
    247 +			xw.XdndSourceWin,
    248 +			xw.XdndTypeList,
    249 +			0,
    250 +			LONG_MAX,
    251 +			False,
    252 +			4,
    253 +			&actualType,
    254 +			&actualFormat,
    255 +			&count,
    256 +			&bytesAfter,
    257 +			(unsigned char**) &formats);
    258 +	} else {
    259 +		count = 0;
    260 +
    261 +		if (e->xclient.data.l[2] != None)
    262 +			real_formats[count++] = e->xclient.data.l[2];
    263 +		if (e->xclient.data.l[3] != None)
    264 +			real_formats[count++] = e->xclient.data.l[3];
    265 +		if (e->xclient.data.l[4] != None)
    266 +			real_formats[count++] = e->xclient.data.l[4];
    267 +
    268 +		formats = real_formats;
    269 +	}
    270 +
    271 +	for (i = 0; i < count; i++) {
    272 +		if (formats[i] == xw.XtextUriList || formats[i] == xw.XtextPlain) {
    273 +			xw.XdndSourceFormat = formats[i];
    274 +			break;
    275 +		}
    276 +	}
    277 +
    278 +	if (list)
    279 +		XFree(formats);
    280 +}
    281 +
    282 +void
    283 +xdndpos(XEvent *e)
    284 +{
    285 +	const int32_t xabs = (e->xclient.data.l[2] >> 16) & 0xffff;
    286 +	const int32_t yabs = (e->xclient.data.l[2]) & 0xffff;
    287 +	Window dummy;
    288 +	int32_t xpos, ypos;
    289 +	XEvent reply = { ClientMessage };
    290 +
    291 +	reply.xclient.window = xw.XdndSourceWin;
    292 +	reply.xclient.format = 32;
    293 +	reply.xclient.data.l[0] = (long) xw.win;
    294 +	reply.xclient.data.l[2] = 0;
    295 +	reply.xclient.data.l[3] = 0;
    296 +
    297 +	XTranslateCoordinates((Display*) xw.dpy,
    298 +		XDefaultRootWindow((Display*) xw.dpy),
    299 +		(Window) xw.win,
    300 +		xabs, yabs,
    301 +		&xpos, &ypos,
    302 +		&dummy);
    303 +
    304 +	reply.xclient.message_type = xw.XdndStatus;
    305 +
    306 +	if (xw.XdndSourceFormat) {
    307 +		reply.xclient.data.l[1] = 1;
    308 +		if (xw.XdndSourceVersion >= 2)
    309 +			reply.xclient.data.l[4] = xw.XdndActionCopy;
    310 +	}
    311 +
    312 +	XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask,
    313 +			&reply);
    314 +	XFlush((Display*) xw.dpy);
    315 +}
    316 +
    317 +void
    318 +xdnddrop(XEvent *e)
    319 +{
    320 +	Time time = CurrentTime;
    321 +	XEvent reply = { ClientMessage };
    322 +
    323 +	reply.xclient.window = xw.XdndSourceWin;
    324 +	reply.xclient.format = 32;
    325 +	reply.xclient.data.l[0] = (long) xw.win;
    326 +	reply.xclient.data.l[2] = 0;
    327 +	reply.xclient.data.l[3] = 0;
    328 +
    329 +	if (xw.XdndSourceFormat) {
    330 +		if (xw.XdndSourceVersion >= 1)
    331 +			time = e->xclient.data.l[2];
    332 +
    333 +		XConvertSelection((Display*) xw.dpy, xw.XdndSelection,
    334 +				xw.XdndSourceFormat, xw.XdndSelection, (Window) xw.win, time);
    335 +	} else if (xw.XdndSourceVersion >= 2) {
    336 +		reply.xclient.message_type = xw.XdndFinished;
    337 +
    338 +		XSendEvent((Display*) xw.dpy, xw.XdndSourceWin,
    339 +				False, NoEventMask, &reply);
    340 +		XFlush((Display*) xw.dpy);
    341  	}
    342  }
    343