| 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 |