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