st-drag-n-drop-0.9.2.diff - 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) - … | |
28 + (c) >= 'a' && (c) <= 'f' ? (c) - 'a' + … | |
29 + (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + … | |
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, Xdnd… | |
43 + XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndAct… | |
44 + XdndActionLink, XdndActionAsk, XdndActionPrivate, XtextUri… | |
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, AnyPropertyTyp… | |
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, &actualForma… | |
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, … | |
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_I… | |
143 + /* handle %xx escape sequences in url e.g. %20 … | |
144 + c = (char)((HEX_TO_INT(src[1]) << 4) | HEX_TO_I… | |
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",… | |
204 + xw.XtextUriList = XInternAtom((Display*) xw.dpy, "text/uri-list… | |
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, PropModeRe… | |
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.X… | |
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, NoEventM… | |
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, … | |
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 |