st-drag-n-drop-0.9.2.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) 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