dmenu-alpha-20250614-b1e217b.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dmenu-alpha-20250614-b1e217b.diff (53189B)
       ---
            1 diff --git a/config.def.h b/config.def.h
            2 index 1edb647..809c96e 100644
            3 --- a/config.def.h
            4 +++ b/config.def.h
            5 @@ -2,6 +2,7 @@
            6  /* Default settings; can be overriden by command line. */
            7  
            8  static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */
            9 +static const unsigned int alpha = 0xff;     /* Amount of opacity. 0xff is opaque             */
           10  /* -fn option overrides fonts[0]; default X11 font or font set */
           11  static const char *fonts[] = {
           12          "monospace:size=10"
           13 @@ -13,6 +14,12 @@ static const char *colors[SchemeLast][2] = {
           14          [SchemeSel] = { "#eeeeee", "#005577" },
           15          [SchemeOut] = { "#000000", "#00ffff" },
           16  };
           17 +
           18 +static const unsigned int alphas[SchemeLast][2] = {
           19 +        [SchemeNorm] = { OPAQUE, alpha },
           20 +        [SchemeSel] = { OPAQUE, alpha },
           21 +        [SchemeOut] = { OPAQUE, alpha },
           22 +};
           23  /* -l option; if nonzero, dmenu uses vertical list with given number of lines */
           24  static unsigned int lines      = 0;
           25  
           26 diff --git a/config.mk b/config.mk
           27 index 137f7c8..64c3b06 100644
           28 --- a/config.mk
           29 +++ b/config.mk
           30 @@ -21,7 +21,7 @@ FREETYPEINC = /usr/include/freetype2
           31  
           32  # includes and libs
           33  INCS = -I$(X11INC) -I$(FREETYPEINC)
           34 -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
           35 +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender
           36  
           37  # flags
           38  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
           39 diff --git a/dmenu.c b/dmenu.c
           40 index fd49549..85bb73a 100644
           41 --- a/dmenu.c
           42 +++ b/dmenu.c
           43 @@ -10,10 +10,12 @@
           44  
           45  #include <X11/Xlib.h>
           46  #include <X11/Xatom.h>
           47 +#include <X11/Xproto.h>
           48  #include <X11/Xutil.h>
           49  #ifdef XINERAMA
           50  #include <X11/extensions/Xinerama.h>
           51  #endif
           52 +#include <X11/extensions/Xrender.h>
           53  #include <X11/Xft/Xft.h>
           54  
           55  #include "drw.h"
           56 @@ -24,6 +26,8 @@
           57                               * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
           58  #define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad)
           59  
           60 +#define OPAQUE                0xffu
           61 +
           62  /* enums */
           63  enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
           64  
           65 @@ -52,10 +56,16 @@ static XIC xic;
           66  static Drw *drw;
           67  static Clr *scheme[SchemeLast];
           68  
           69 +static int useargb = 0;
           70 +static Visual *visual;
           71 +static int depth;
           72 +static Colormap cmap;
           73 +
           74  #include "config.h"
           75  
           76  static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
           77  static char *(*fstrstr)(const char *, const char *) = strstr;
           78 +static void xinitvisual();
           79  
           80  static unsigned int
           81  textw_clamp(const char *str, unsigned int n)
           82 @@ -627,7 +637,7 @@ setup(void)
           83  #endif
           84          /* init appearance */
           85          for (j = 0; j < SchemeLast; j++)
           86 -                scheme[j] = drw_scm_create(drw, colors[j], 2);
           87 +                scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2);
           88  
           89          clip = XInternAtom(dpy, "CLIPBOARD",   False);
           90          utf8 = XInternAtom(dpy, "UTF8_STRING", False);
           91 @@ -682,11 +692,12 @@ setup(void)
           92  
           93          /* create menu window */
           94          swa.override_redirect = True;
           95 -        swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
           96 +        swa.border_pixel = 0;
           97 +        swa.colormap = cmap;
           98          swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
           99          win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
          100 -                            CopyFromParent, CopyFromParent, CopyFromParent,
          101 -                            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
          102 +                            depth, CopyFromParent, visual,
          103 +                            CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
          104          XSetClassHint(dpy, win, &ch);
          105  
          106          /* input methods */
          107 @@ -771,7 +782,8 @@ main(int argc, char *argv[])
          108          if (!XGetWindowAttributes(dpy, parentwin, &wa))
          109                  die("could not get embedding window attributes: 0x%lx",
          110                      parentwin);
          111 -        drw = drw_create(dpy, screen, root, wa.width, wa.height);
          112 +        xinitvisual();
          113 +        drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
          114          if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
          115                  die("no fonts could be loaded.");
          116          lrpad = drw->fonts->h;
          117 @@ -793,3 +805,40 @@ main(int argc, char *argv[])
          118  
          119          return 1; /* unreachable */
          120  }
          121 +
          122 +void
          123 +xinitvisual()
          124 +{
          125 +        XVisualInfo *infos;
          126 +        XRenderPictFormat *fmt;
          127 +        int nitems;
          128 +        int i;
          129 +
          130 +        XVisualInfo tpl = {
          131 +                .screen = screen,
          132 +                .depth = 32,
          133 +                .class = TrueColor
          134 +        };
          135 +        long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
          136 +
          137 +        infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
          138 +        visual = NULL;
          139 +        for(i = 0; i < nitems; i ++) {
          140 +                fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
          141 +                if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
          142 +                         visual = infos[i].visual;
          143 +                         depth = infos[i].depth;
          144 +                         cmap = XCreateColormap(dpy, root, visual, AllocNone);
          145 +                         useargb = 1;
          146 +                         break;
          147 +                }
          148 +        }
          149 +
          150 +        XFree(infos);
          151 +
          152 +        if (! visual) {
          153 +                visual = DefaultVisual(dpy, screen);
          154 +                depth = DefaultDepth(dpy, screen);
          155 +                cmap = DefaultColormap(dpy, screen);
          156 +        }
          157 +}
          158 diff --git a/dmenu.c.orig b/dmenu.c.orig
          159 new file mode 100644
          160 index 0000000..fd49549
          161 --- /dev/null
          162 +++ b/dmenu.c.orig
          163 @@ -0,0 +1,795 @@
          164 +/* See LICENSE file for copyright and license details. */
          165 +#include <ctype.h>
          166 +#include <locale.h>
          167 +#include <stdio.h>
          168 +#include <stdlib.h>
          169 +#include <string.h>
          170 +#include <strings.h>
          171 +#include <time.h>
          172 +#include <unistd.h>
          173 +
          174 +#include <X11/Xlib.h>
          175 +#include <X11/Xatom.h>
          176 +#include <X11/Xutil.h>
          177 +#ifdef XINERAMA
          178 +#include <X11/extensions/Xinerama.h>
          179 +#endif
          180 +#include <X11/Xft/Xft.h>
          181 +
          182 +#include "drw.h"
          183 +#include "util.h"
          184 +
          185 +/* macros */
          186 +#define INTERSECT(x,y,w,h,r)  (MAX(0, MIN((x)+(w),(r).x_org+(r).width)  - MAX((x),(r).x_org)) \
          187 +                             * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
          188 +#define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad)
          189 +
          190 +/* enums */
          191 +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
          192 +
          193 +struct item {
          194 +        char *text;
          195 +        struct item *left, *right;
          196 +        int out;
          197 +};
          198 +
          199 +static char text[BUFSIZ] = "";
          200 +static char *embed;
          201 +static int bh, mw, mh;
          202 +static int inputw = 0, promptw;
          203 +static int lrpad; /* sum of left and right padding */
          204 +static size_t cursor;
          205 +static struct item *items = NULL;
          206 +static struct item *matches, *matchend;
          207 +static struct item *prev, *curr, *next, *sel;
          208 +static int mon = -1, screen;
          209 +
          210 +static Atom clip, utf8;
          211 +static Display *dpy;
          212 +static Window root, parentwin, win;
          213 +static XIC xic;
          214 +
          215 +static Drw *drw;
          216 +static Clr *scheme[SchemeLast];
          217 +
          218 +#include "config.h"
          219 +
          220 +static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
          221 +static char *(*fstrstr)(const char *, const char *) = strstr;
          222 +
          223 +static unsigned int
          224 +textw_clamp(const char *str, unsigned int n)
          225 +{
          226 +        unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
          227 +        return MIN(w, n);
          228 +}
          229 +
          230 +static void
          231 +appenditem(struct item *item, struct item **list, struct item **last)
          232 +{
          233 +        if (*last)
          234 +                (*last)->right = item;
          235 +        else
          236 +                *list = item;
          237 +
          238 +        item->left = *last;
          239 +        item->right = NULL;
          240 +        *last = item;
          241 +}
          242 +
          243 +static void
          244 +calcoffsets(void)
          245 +{
          246 +        int i, n;
          247 +
          248 +        if (lines > 0)
          249 +                n = lines * bh;
          250 +        else
          251 +                n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
          252 +        /* calculate which items will begin the next page and previous page */
          253 +        for (i = 0, next = curr; next; next = next->right)
          254 +                if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
          255 +                        break;
          256 +        for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
          257 +                if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
          258 +                        break;
          259 +}
          260 +
          261 +static void
          262 +cleanup(void)
          263 +{
          264 +        size_t i;
          265 +
          266 +        XUngrabKeyboard(dpy, CurrentTime);
          267 +        for (i = 0; i < SchemeLast; i++)
          268 +                free(scheme[i]);
          269 +        for (i = 0; items && items[i].text; ++i)
          270 +                free(items[i].text);
          271 +        free(items);
          272 +        drw_free(drw);
          273 +        XSync(dpy, False);
          274 +        XCloseDisplay(dpy);
          275 +}
          276 +
          277 +static char *
          278 +cistrstr(const char *h, const char *n)
          279 +{
          280 +        size_t i;
          281 +
          282 +        if (!n[0])
          283 +                return (char *)h;
          284 +
          285 +        for (; *h; ++h) {
          286 +                for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
          287 +                            tolower((unsigned char)h[i]); ++i)
          288 +                        ;
          289 +                if (n[i] == '\0')
          290 +                        return (char *)h;
          291 +        }
          292 +        return NULL;
          293 +}
          294 +
          295 +static int
          296 +drawitem(struct item *item, int x, int y, int w)
          297 +{
          298 +        if (item == sel)
          299 +                drw_setscheme(drw, scheme[SchemeSel]);
          300 +        else if (item->out)
          301 +                drw_setscheme(drw, scheme[SchemeOut]);
          302 +        else
          303 +                drw_setscheme(drw, scheme[SchemeNorm]);
          304 +
          305 +        return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
          306 +}
          307 +
          308 +static void
          309 +drawmenu(void)
          310 +{
          311 +        unsigned int curpos;
          312 +        struct item *item;
          313 +        int x = 0, y = 0, w;
          314 +
          315 +        drw_setscheme(drw, scheme[SchemeNorm]);
          316 +        drw_rect(drw, 0, 0, mw, mh, 1, 1);
          317 +
          318 +        if (prompt && *prompt) {
          319 +                drw_setscheme(drw, scheme[SchemeSel]);
          320 +                x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
          321 +        }
          322 +        /* draw input field */
          323 +        w = (lines > 0 || !matches) ? mw - x : inputw;
          324 +        drw_setscheme(drw, scheme[SchemeNorm]);
          325 +        drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
          326 +
          327 +        curpos = TEXTW(text) - TEXTW(&text[cursor]);
          328 +        if ((curpos += lrpad / 2 - 1) < w) {
          329 +                drw_setscheme(drw, scheme[SchemeNorm]);
          330 +                drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
          331 +        }
          332 +
          333 +        if (lines > 0) {
          334 +                /* draw vertical list */
          335 +                for (item = curr; item != next; item = item->right)
          336 +                        drawitem(item, x, y += bh, mw - x);
          337 +        } else if (matches) {
          338 +                /* draw horizontal list */
          339 +                x += inputw;
          340 +                w = TEXTW("<");
          341 +                if (curr->left) {
          342 +                        drw_setscheme(drw, scheme[SchemeNorm]);
          343 +                        drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
          344 +                }
          345 +                x += w;
          346 +                for (item = curr; item != next; item = item->right)
          347 +                        x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
          348 +                if (next) {
          349 +                        w = TEXTW(">");
          350 +                        drw_setscheme(drw, scheme[SchemeNorm]);
          351 +                        drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
          352 +                }
          353 +        }
          354 +        drw_map(drw, win, 0, 0, mw, mh);
          355 +}
          356 +
          357 +static void
          358 +grabfocus(void)
          359 +{
          360 +        struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000  };
          361 +        Window focuswin;
          362 +        int i, revertwin;
          363 +
          364 +        for (i = 0; i < 100; ++i) {
          365 +                XGetInputFocus(dpy, &focuswin, &revertwin);
          366 +                if (focuswin == win)
          367 +                        return;
          368 +                XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
          369 +                nanosleep(&ts, NULL);
          370 +        }
          371 +        die("cannot grab focus");
          372 +}
          373 +
          374 +static void
          375 +grabkeyboard(void)
          376 +{
          377 +        struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000  };
          378 +        int i;
          379 +
          380 +        if (embed)
          381 +                return;
          382 +        /* try to grab keyboard, we may have to wait for another process to ungrab */
          383 +        for (i = 0; i < 1000; i++) {
          384 +                if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
          385 +                                  GrabModeAsync, CurrentTime) == GrabSuccess)
          386 +                        return;
          387 +                nanosleep(&ts, NULL);
          388 +        }
          389 +        die("cannot grab keyboard");
          390 +}
          391 +
          392 +static void
          393 +match(void)
          394 +{
          395 +        static char **tokv = NULL;
          396 +        static int tokn = 0;
          397 +
          398 +        char buf[sizeof text], *s;
          399 +        int i, tokc = 0;
          400 +        size_t len, textsize;
          401 +        struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
          402 +
          403 +        strcpy(buf, text);
          404 +        /* separate input text into tokens to be matched individually */
          405 +        for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
          406 +                if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
          407 +                        die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
          408 +        len = tokc ? strlen(tokv[0]) : 0;
          409 +
          410 +        matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
          411 +        textsize = strlen(text) + 1;
          412 +        for (item = items; item && item->text; item++) {
          413 +                for (i = 0; i < tokc; i++)
          414 +                        if (!fstrstr(item->text, tokv[i]))
          415 +                                break;
          416 +                if (i != tokc) /* not all tokens match */
          417 +                        continue;
          418 +                /* exact matches go first, then prefixes, then substrings */
          419 +                if (!tokc || !fstrncmp(text, item->text, textsize))
          420 +                        appenditem(item, &matches, &matchend);
          421 +                else if (!fstrncmp(tokv[0], item->text, len))
          422 +                        appenditem(item, &lprefix, &prefixend);
          423 +                else
          424 +                        appenditem(item, &lsubstr, &substrend);
          425 +        }
          426 +        if (lprefix) {
          427 +                if (matches) {
          428 +                        matchend->right = lprefix;
          429 +                        lprefix->left = matchend;
          430 +                } else
          431 +                        matches = lprefix;
          432 +                matchend = prefixend;
          433 +        }
          434 +        if (lsubstr) {
          435 +                if (matches) {
          436 +                        matchend->right = lsubstr;
          437 +                        lsubstr->left = matchend;
          438 +                } else
          439 +                        matches = lsubstr;
          440 +                matchend = substrend;
          441 +        }
          442 +        curr = sel = matches;
          443 +        calcoffsets();
          444 +}
          445 +
          446 +static void
          447 +insert(const char *str, ssize_t n)
          448 +{
          449 +        if (strlen(text) + n > sizeof text - 1)
          450 +                return;
          451 +        /* move existing text out of the way, insert new text, and update cursor */
          452 +        memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
          453 +        if (n > 0)
          454 +                memcpy(&text[cursor], str, n);
          455 +        cursor += n;
          456 +        match();
          457 +}
          458 +
          459 +static size_t
          460 +nextrune(int inc)
          461 +{
          462 +        ssize_t n;
          463 +
          464 +        /* return location of next utf8 rune in the given direction (+1 or -1) */
          465 +        for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
          466 +                ;
          467 +        return n;
          468 +}
          469 +
          470 +static void
          471 +movewordedge(int dir)
          472 +{
          473 +        if (dir < 0) { /* move cursor to the start of the word*/
          474 +                while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
          475 +                        cursor = nextrune(-1);
          476 +                while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
          477 +                        cursor = nextrune(-1);
          478 +        } else { /* move cursor to the end of the word */
          479 +                while (text[cursor] && strchr(worddelimiters, text[cursor]))
          480 +                        cursor = nextrune(+1);
          481 +                while (text[cursor] && !strchr(worddelimiters, text[cursor]))
          482 +                        cursor = nextrune(+1);
          483 +        }
          484 +}
          485 +
          486 +static void
          487 +keypress(XKeyEvent *ev)
          488 +{
          489 +        char buf[64];
          490 +        int len;
          491 +        KeySym ksym = NoSymbol;
          492 +        Status status;
          493 +
          494 +        len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
          495 +        switch (status) {
          496 +        default: /* XLookupNone, XBufferOverflow */
          497 +                return;
          498 +        case XLookupChars: /* composed string from input method */
          499 +                goto insert;
          500 +        case XLookupKeySym:
          501 +        case XLookupBoth: /* a KeySym and a string are returned: use keysym */
          502 +                break;
          503 +        }
          504 +
          505 +        if (ev->state & ControlMask) {
          506 +                switch(ksym) {
          507 +                case XK_a: ksym = XK_Home;      break;
          508 +                case XK_b: ksym = XK_Left;      break;
          509 +                case XK_c: ksym = XK_Escape;    break;
          510 +                case XK_d: ksym = XK_Delete;    break;
          511 +                case XK_e: ksym = XK_End;       break;
          512 +                case XK_f: ksym = XK_Right;     break;
          513 +                case XK_g: ksym = XK_Escape;    break;
          514 +                case XK_h: ksym = XK_BackSpace; break;
          515 +                case XK_i: ksym = XK_Tab;       break;
          516 +                case XK_j: /* fallthrough */
          517 +                case XK_J: /* fallthrough */
          518 +                case XK_m: /* fallthrough */
          519 +                case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
          520 +                case XK_n: ksym = XK_Down;      break;
          521 +                case XK_p: ksym = XK_Up;        break;
          522 +
          523 +                case XK_k: /* delete right */
          524 +                        text[cursor] = '\0';
          525 +                        match();
          526 +                        break;
          527 +                case XK_u: /* delete left */
          528 +                        insert(NULL, 0 - cursor);
          529 +                        break;
          530 +                case XK_w: /* delete word */
          531 +                        while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
          532 +                                insert(NULL, nextrune(-1) - cursor);
          533 +                        while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
          534 +                                insert(NULL, nextrune(-1) - cursor);
          535 +                        break;
          536 +                case XK_y: /* paste selection */
          537 +                case XK_Y:
          538 +                        XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
          539 +                                          utf8, utf8, win, CurrentTime);
          540 +                        return;
          541 +                case XK_Left:
          542 +                case XK_KP_Left:
          543 +                        movewordedge(-1);
          544 +                        goto draw;
          545 +                case XK_Right:
          546 +                case XK_KP_Right:
          547 +                        movewordedge(+1);
          548 +                        goto draw;
          549 +                case XK_Return:
          550 +                case XK_KP_Enter:
          551 +                        break;
          552 +                case XK_bracketleft:
          553 +                        cleanup();
          554 +                        exit(1);
          555 +                default:
          556 +                        return;
          557 +                }
          558 +        } else if (ev->state & Mod1Mask) {
          559 +                switch(ksym) {
          560 +                case XK_b:
          561 +                        movewordedge(-1);
          562 +                        goto draw;
          563 +                case XK_f:
          564 +                        movewordedge(+1);
          565 +                        goto draw;
          566 +                case XK_g: ksym = XK_Home;  break;
          567 +                case XK_G: ksym = XK_End;   break;
          568 +                case XK_h: ksym = XK_Up;    break;
          569 +                case XK_j: ksym = XK_Next;  break;
          570 +                case XK_k: ksym = XK_Prior; break;
          571 +                case XK_l: ksym = XK_Down;  break;
          572 +                default:
          573 +                        return;
          574 +                }
          575 +        }
          576 +
          577 +        switch(ksym) {
          578 +        default:
          579 +insert:
          580 +                if (!iscntrl((unsigned char)*buf))
          581 +                        insert(buf, len);
          582 +                break;
          583 +        case XK_Delete:
          584 +        case XK_KP_Delete:
          585 +                if (text[cursor] == '\0')
          586 +                        return;
          587 +                cursor = nextrune(+1);
          588 +                /* fallthrough */
          589 +        case XK_BackSpace:
          590 +                if (cursor == 0)
          591 +                        return;
          592 +                insert(NULL, nextrune(-1) - cursor);
          593 +                break;
          594 +        case XK_End:
          595 +        case XK_KP_End:
          596 +                if (text[cursor] != '\0') {
          597 +                        cursor = strlen(text);
          598 +                        break;
          599 +                }
          600 +                if (next) {
          601 +                        /* jump to end of list and position items in reverse */
          602 +                        curr = matchend;
          603 +                        calcoffsets();
          604 +                        curr = prev;
          605 +                        calcoffsets();
          606 +                        while (next && (curr = curr->right))
          607 +                                calcoffsets();
          608 +                }
          609 +                sel = matchend;
          610 +                break;
          611 +        case XK_Escape:
          612 +                cleanup();
          613 +                exit(1);
          614 +        case XK_Home:
          615 +        case XK_KP_Home:
          616 +                if (sel == matches) {
          617 +                        cursor = 0;
          618 +                        break;
          619 +                }
          620 +                sel = curr = matches;
          621 +                calcoffsets();
          622 +                break;
          623 +        case XK_Left:
          624 +        case XK_KP_Left:
          625 +                if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
          626 +                        cursor = nextrune(-1);
          627 +                        break;
          628 +                }
          629 +                if (lines > 0)
          630 +                        return;
          631 +                /* fallthrough */
          632 +        case XK_Up:
          633 +        case XK_KP_Up:
          634 +                if (sel && sel->left && (sel = sel->left)->right == curr) {
          635 +                        curr = prev;
          636 +                        calcoffsets();
          637 +                }
          638 +                break;
          639 +        case XK_Next:
          640 +        case XK_KP_Next:
          641 +                if (!next)
          642 +                        return;
          643 +                sel = curr = next;
          644 +                calcoffsets();
          645 +                break;
          646 +        case XK_Prior:
          647 +        case XK_KP_Prior:
          648 +                if (!prev)
          649 +                        return;
          650 +                sel = curr = prev;
          651 +                calcoffsets();
          652 +                break;
          653 +        case XK_Return:
          654 +        case XK_KP_Enter:
          655 +                puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
          656 +                if (!(ev->state & ControlMask)) {
          657 +                        cleanup();
          658 +                        exit(0);
          659 +                }
          660 +                if (sel)
          661 +                        sel->out = 1;
          662 +                break;
          663 +        case XK_Right:
          664 +        case XK_KP_Right:
          665 +                if (text[cursor] != '\0') {
          666 +                        cursor = nextrune(+1);
          667 +                        break;
          668 +                }
          669 +                if (lines > 0)
          670 +                        return;
          671 +                /* fallthrough */
          672 +        case XK_Down:
          673 +        case XK_KP_Down:
          674 +                if (sel && sel->right && (sel = sel->right) == next) {
          675 +                        curr = next;
          676 +                        calcoffsets();
          677 +                }
          678 +                break;
          679 +        case XK_Tab:
          680 +                if (!sel)
          681 +                        return;
          682 +                cursor = strnlen(sel->text, sizeof text - 1);
          683 +                memcpy(text, sel->text, cursor);
          684 +                text[cursor] = '\0';
          685 +                match();
          686 +                break;
          687 +        }
          688 +
          689 +draw:
          690 +        drawmenu();
          691 +}
          692 +
          693 +static void
          694 +paste(void)
          695 +{
          696 +        char *p, *q;
          697 +        int di;
          698 +        unsigned long dl;
          699 +        Atom da;
          700 +
          701 +        /* we have been given the current selection, now insert it into input */
          702 +        if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
          703 +                           utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
          704 +            == Success && p) {
          705 +                insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
          706 +                XFree(p);
          707 +        }
          708 +        drawmenu();
          709 +}
          710 +
          711 +static void
          712 +readstdin(void)
          713 +{
          714 +        char *line = NULL;
          715 +        size_t i, itemsiz = 0, linesiz = 0;
          716 +        ssize_t len;
          717 +
          718 +        /* read each line from stdin and add it to the item list */
          719 +        for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) {
          720 +                if (i + 1 >= itemsiz) {
          721 +                        itemsiz += 256;
          722 +                        if (!(items = realloc(items, itemsiz * sizeof(*items))))
          723 +                                die("cannot realloc %zu bytes:", itemsiz * sizeof(*items));
          724 +                }
          725 +                if (line[len - 1] == '\n')
          726 +                        line[len - 1] = '\0';
          727 +                if (!(items[i].text = strdup(line)))
          728 +                        die("strdup:");
          729 +
          730 +                items[i].out = 0;
          731 +        }
          732 +        free(line);
          733 +        if (items)
          734 +                items[i].text = NULL;
          735 +        lines = MIN(lines, i);
          736 +}
          737 +
          738 +static void
          739 +run(void)
          740 +{
          741 +        XEvent ev;
          742 +
          743 +        while (!XNextEvent(dpy, &ev)) {
          744 +                if (XFilterEvent(&ev, win))
          745 +                        continue;
          746 +                switch(ev.type) {
          747 +                case DestroyNotify:
          748 +                        if (ev.xdestroywindow.window != win)
          749 +                                break;
          750 +                        cleanup();
          751 +                        exit(1);
          752 +                case Expose:
          753 +                        if (ev.xexpose.count == 0)
          754 +                                drw_map(drw, win, 0, 0, mw, mh);
          755 +                        break;
          756 +                case FocusIn:
          757 +                        /* regrab focus from parent window */
          758 +                        if (ev.xfocus.window != win)
          759 +                                grabfocus();
          760 +                        break;
          761 +                case KeyPress:
          762 +                        keypress(&ev.xkey);
          763 +                        break;
          764 +                case SelectionNotify:
          765 +                        if (ev.xselection.property == utf8)
          766 +                                paste();
          767 +                        break;
          768 +                case VisibilityNotify:
          769 +                        if (ev.xvisibility.state != VisibilityUnobscured)
          770 +                                XRaiseWindow(dpy, win);
          771 +                        break;
          772 +                }
          773 +        }
          774 +}
          775 +
          776 +static void
          777 +setup(void)
          778 +{
          779 +        int x, y, i, j;
          780 +        unsigned int du;
          781 +        XSetWindowAttributes swa;
          782 +        XIM xim;
          783 +        Window w, dw, *dws;
          784 +        XWindowAttributes wa;
          785 +        XClassHint ch = {"dmenu", "dmenu"};
          786 +#ifdef XINERAMA
          787 +        XineramaScreenInfo *info;
          788 +        Window pw;
          789 +        int a, di, n, area = 0;
          790 +#endif
          791 +        /* init appearance */
          792 +        for (j = 0; j < SchemeLast; j++)
          793 +                scheme[j] = drw_scm_create(drw, colors[j], 2);
          794 +
          795 +        clip = XInternAtom(dpy, "CLIPBOARD",   False);
          796 +        utf8 = XInternAtom(dpy, "UTF8_STRING", False);
          797 +
          798 +        /* calculate menu geometry */
          799 +        bh = drw->fonts->h + 2;
          800 +        lines = MAX(lines, 0);
          801 +        mh = (lines + 1) * bh;
          802 +#ifdef XINERAMA
          803 +        i = 0;
          804 +        if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
          805 +                XGetInputFocus(dpy, &w, &di);
          806 +                if (mon >= 0 && mon < n)
          807 +                        i = mon;
          808 +                else if (w != root && w != PointerRoot && w != None) {
          809 +                        /* find top-level window containing current input focus */
          810 +                        do {
          811 +                                if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
          812 +                                        XFree(dws);
          813 +                        } while (w != root && w != pw);
          814 +                        /* find xinerama screen with which the window intersects most */
          815 +                        if (XGetWindowAttributes(dpy, pw, &wa))
          816 +                                for (j = 0; j < n; j++)
          817 +                                        if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
          818 +                                                area = a;
          819 +                                                i = j;
          820 +                                        }
          821 +                }
          822 +                /* no focused window is on screen, so use pointer location instead */
          823 +                if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
          824 +                        for (i = 0; i < n; i++)
          825 +                                if (INTERSECT(x, y, 1, 1, info[i]) != 0)
          826 +                                        break;
          827 +
          828 +                x = info[i].x_org;
          829 +                y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
          830 +                mw = info[i].width;
          831 +                XFree(info);
          832 +        } else
          833 +#endif
          834 +        {
          835 +                if (!XGetWindowAttributes(dpy, parentwin, &wa))
          836 +                        die("could not get embedding window attributes: 0x%lx",
          837 +                            parentwin);
          838 +                x = 0;
          839 +                y = topbar ? 0 : wa.height - mh;
          840 +                mw = wa.width;
          841 +        }
          842 +        promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
          843 +        inputw = mw / 3; /* input width: ~33% of monitor width */
          844 +        match();
          845 +
          846 +        /* create menu window */
          847 +        swa.override_redirect = True;
          848 +        swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
          849 +        swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
          850 +        win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
          851 +                            CopyFromParent, CopyFromParent, CopyFromParent,
          852 +                            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
          853 +        XSetClassHint(dpy, win, &ch);
          854 +
          855 +        /* input methods */
          856 +        if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
          857 +                die("XOpenIM failed: could not open input device");
          858 +
          859 +        xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
          860 +                        XNClientWindow, win, XNFocusWindow, win, NULL);
          861 +
          862 +        XMapRaised(dpy, win);
          863 +        if (embed) {
          864 +                XReparentWindow(dpy, win, parentwin, x, y);
          865 +                XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
          866 +                if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
          867 +                        for (i = 0; i < du && dws[i] != win; ++i)
          868 +                                XSelectInput(dpy, dws[i], FocusChangeMask);
          869 +                        XFree(dws);
          870 +                }
          871 +                grabfocus();
          872 +        }
          873 +        drw_resize(drw, mw, mh);
          874 +        drawmenu();
          875 +}
          876 +
          877 +static void
          878 +usage(void)
          879 +{
          880 +        die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
          881 +            "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");
          882 +}
          883 +
          884 +int
          885 +main(int argc, char *argv[])
          886 +{
          887 +        XWindowAttributes wa;
          888 +        int i, fast = 0;
          889 +
          890 +        for (i = 1; i < argc; i++)
          891 +                /* these options take no arguments */
          892 +                if (!strcmp(argv[i], "-v")) {      /* prints version information */
          893 +                        puts("dmenu-"VERSION);
          894 +                        exit(0);
          895 +                } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
          896 +                        topbar = 0;
          897 +                else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
          898 +                        fast = 1;
          899 +                else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
          900 +                        fstrncmp = strncasecmp;
          901 +                        fstrstr = cistrstr;
          902 +                } else if (i + 1 == argc)
          903 +                        usage();
          904 +                /* these options take one argument */
          905 +                else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */
          906 +                        lines = atoi(argv[++i]);
          907 +                else if (!strcmp(argv[i], "-m"))
          908 +                        mon = atoi(argv[++i]);
          909 +                else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */
          910 +                        prompt = argv[++i];
          911 +                else if (!strcmp(argv[i], "-fn"))  /* font or font set */
          912 +                        fonts[0] = argv[++i];
          913 +                else if (!strcmp(argv[i], "-nb"))  /* normal background color */
          914 +                        colors[SchemeNorm][ColBg] = argv[++i];
          915 +                else if (!strcmp(argv[i], "-nf"))  /* normal foreground color */
          916 +                        colors[SchemeNorm][ColFg] = argv[++i];
          917 +                else if (!strcmp(argv[i], "-sb"))  /* selected background color */
          918 +                        colors[SchemeSel][ColBg] = argv[++i];
          919 +                else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */
          920 +                        colors[SchemeSel][ColFg] = argv[++i];
          921 +                else if (!strcmp(argv[i], "-w"))   /* embedding window id */
          922 +                        embed = argv[++i];
          923 +                else
          924 +                        usage();
          925 +
          926 +        if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
          927 +                fputs("warning: no locale support\n", stderr);
          928 +        if (!(dpy = XOpenDisplay(NULL)))
          929 +                die("cannot open display");
          930 +        screen = DefaultScreen(dpy);
          931 +        root = RootWindow(dpy, screen);
          932 +        if (!embed || !(parentwin = strtol(embed, NULL, 0)))
          933 +                parentwin = root;
          934 +        if (!XGetWindowAttributes(dpy, parentwin, &wa))
          935 +                die("could not get embedding window attributes: 0x%lx",
          936 +                    parentwin);
          937 +        drw = drw_create(dpy, screen, root, wa.width, wa.height);
          938 +        if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
          939 +                die("no fonts could be loaded.");
          940 +        lrpad = drw->fonts->h;
          941 +
          942 +#ifdef __OpenBSD__
          943 +        if (pledge("stdio rpath", NULL) == -1)
          944 +                die("pledge");
          945 +#endif
          946 +
          947 +        if (fast && !isatty(0)) {
          948 +                grabkeyboard();
          949 +                readstdin();
          950 +        } else {
          951 +                readstdin();
          952 +                grabkeyboard();
          953 +        }
          954 +        setup();
          955 +        run();
          956 +
          957 +        return 1; /* unreachable */
          958 +}
          959 diff --git a/dmenu.c.rej b/dmenu.c.rej
          960 new file mode 100644
          961 index 0000000..ea19a32
          962 --- /dev/null
          963 +++ b/dmenu.c.rej
          964 @@ -0,0 +1,19 @@
          965 +--- dmenu.c
          966 ++++ dmenu.c
          967 +@@ -692,11 +702,13 @@ setup(void)
          968 + 
          969 +         /* create menu window */
          970 +         swa.override_redirect = True;
          971 +-        swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
          972 ++        swa.background_pixel = 0;
          973 ++        swa.border_pixel = 0;
          974 ++        swa.colormap = cmap;
          975 +         swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
          976 +         win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
          977 +-                            CopyFromParent, CopyFromParent, CopyFromParent,
          978 +-                            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
          979 ++                            depth, CopyFromParent, visual,
          980 ++                            CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
          981 +         XSetClassHint(dpy, win, &ch);
          982 + 
          983 + 
          984 diff --git a/drw.c b/drw.c
          985 index c41e6af..f8d4ac2 100644
          986 --- a/drw.c
          987 +++ b/drw.c
          988 @@ -47,7 +47,7 @@ utf8decode(const char *s_in, long *u, int *err)
          989  }
          990  
          991  Drw *
          992 -drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
          993 +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
          994  {
          995          Drw *drw = ecalloc(1, sizeof(Drw));
          996  
          997 @@ -56,8 +56,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
          998          drw->root = root;
          999          drw->w = w;
         1000          drw->h = h;
         1001 -        drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
         1002 -        drw->gc = XCreateGC(dpy, root, 0, NULL);
         1003 +        drw->visual = visual;
         1004 +        drw->depth = depth;
         1005 +        drw->cmap = cmap;
         1006 +        drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
         1007 +        drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
         1008          XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
         1009  
         1010          return drw;
         1011 @@ -73,7 +76,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
         1012          drw->h = h;
         1013          if (drw->drawable)
         1014                  XFreePixmap(drw->dpy, drw->drawable);
         1015 -        drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
         1016 +        drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
         1017  }
         1018  
         1019  void
         1020 @@ -167,21 +170,22 @@ drw_fontset_free(Fnt *font)
         1021  }
         1022  
         1023  void
         1024 -drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
         1025 +drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
         1026  {
         1027          if (!drw || !dest || !clrname)
         1028                  return;
         1029  
         1030 -        if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
         1031 -                               DefaultColormap(drw->dpy, drw->screen),
         1032 +        if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
         1033                                 clrname, dest))
         1034                  die("error, cannot allocate color '%s'", clrname);
         1035 +
         1036 +        dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
         1037  }
         1038  
         1039  /* Wrapper to create color schemes. The caller has to call free(3) on the
         1040   * returned color scheme when done using it. */
         1041  Clr *
         1042 -drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
         1043 +drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
         1044  {
         1045          size_t i;
         1046          Clr *ret;
         1047 @@ -191,7 +195,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
         1048                  return NULL;
         1049  
         1050          for (i = 0; i < clrcount; i++)
         1051 -                drw_clr_create(drw, &ret[i], clrnames[i]);
         1052 +                drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
         1053          return ret;
         1054  }
         1055  
         1056 @@ -248,11 +252,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
         1057          } else {
         1058                  XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
         1059                  XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
         1060 +                d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
         1061                  if (w < lpad)
         1062                          return x + w;
         1063 -                d = XftDrawCreate(drw->dpy, drw->drawable,
         1064 -                                  DefaultVisual(drw->dpy, drw->screen),
         1065 -                                  DefaultColormap(drw->dpy, drw->screen));
         1066                  x += lpad;
         1067                  w -= lpad;
         1068          }
         1069 diff --git a/drw.c.orig b/drw.c.orig
         1070 new file mode 100644
         1071 index 0000000..c41e6af
         1072 --- /dev/null
         1073 +++ b/drw.c.orig
         1074 @@ -0,0 +1,448 @@
         1075 +/* See LICENSE file for copyright and license details. */
         1076 +#include <stdio.h>
         1077 +#include <stdlib.h>
         1078 +#include <string.h>
         1079 +#include <X11/Xlib.h>
         1080 +#include <X11/Xft/Xft.h>
         1081 +
         1082 +#include "drw.h"
         1083 +#include "util.h"
         1084 +
         1085 +#define UTF_INVALID 0xFFFD
         1086 +
         1087 +static int
         1088 +utf8decode(const char *s_in, long *u, int *err)
         1089 +{
         1090 +        static const unsigned char lens[] = {
         1091 +                /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         1092 +                /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0,  /* invalid */
         1093 +                /* 110XX */ 2, 2, 2, 2,
         1094 +                /* 1110X */ 3, 3,
         1095 +                /* 11110 */ 4,
         1096 +                /* 11111 */ 0,  /* invalid */
         1097 +        };
         1098 +        static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
         1099 +        static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
         1100 +
         1101 +        const unsigned char *s = (const unsigned char *)s_in;
         1102 +        int len = lens[*s >> 3];
         1103 +        *u = UTF_INVALID;
         1104 +        *err = 1;
         1105 +        if (len == 0)
         1106 +                return 1;
         1107 +
         1108 +        long cp = s[0] & leading_mask[len - 1];
         1109 +        for (int i = 1; i < len; ++i) {
         1110 +                if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
         1111 +                        return i;
         1112 +                cp = (cp << 6) | (s[i] & 0x3F);
         1113 +        }
         1114 +        /* out of range, surrogate, overlong encoding */
         1115 +        if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
         1116 +                return len;
         1117 +
         1118 +        *err = 0;
         1119 +        *u = cp;
         1120 +        return len;
         1121 +}
         1122 +
         1123 +Drw *
         1124 +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
         1125 +{
         1126 +        Drw *drw = ecalloc(1, sizeof(Drw));
         1127 +
         1128 +        drw->dpy = dpy;
         1129 +        drw->screen = screen;
         1130 +        drw->root = root;
         1131 +        drw->w = w;
         1132 +        drw->h = h;
         1133 +        drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
         1134 +        drw->gc = XCreateGC(dpy, root, 0, NULL);
         1135 +        XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
         1136 +
         1137 +        return drw;
         1138 +}
         1139 +
         1140 +void
         1141 +drw_resize(Drw *drw, unsigned int w, unsigned int h)
         1142 +{
         1143 +        if (!drw)
         1144 +                return;
         1145 +
         1146 +        drw->w = w;
         1147 +        drw->h = h;
         1148 +        if (drw->drawable)
         1149 +                XFreePixmap(drw->dpy, drw->drawable);
         1150 +        drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
         1151 +}
         1152 +
         1153 +void
         1154 +drw_free(Drw *drw)
         1155 +{
         1156 +        XFreePixmap(drw->dpy, drw->drawable);
         1157 +        XFreeGC(drw->dpy, drw->gc);
         1158 +        drw_fontset_free(drw->fonts);
         1159 +        free(drw);
         1160 +}
         1161 +
         1162 +/* This function is an implementation detail. Library users should use
         1163 + * drw_fontset_create instead.
         1164 + */
         1165 +static Fnt *
         1166 +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
         1167 +{
         1168 +        Fnt *font;
         1169 +        XftFont *xfont = NULL;
         1170 +        FcPattern *pattern = NULL;
         1171 +
         1172 +        if (fontname) {
         1173 +                /* Using the pattern found at font->xfont->pattern does not yield the
         1174 +                 * same substitution results as using the pattern returned by
         1175 +                 * FcNameParse; using the latter results in the desired fallback
         1176 +                 * behaviour whereas the former just results in missing-character
         1177 +                 * rectangles being drawn, at least with some fonts. */
         1178 +                if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
         1179 +                        fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
         1180 +                        return NULL;
         1181 +                }
         1182 +                if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
         1183 +                        fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
         1184 +                        XftFontClose(drw->dpy, xfont);
         1185 +                        return NULL;
         1186 +                }
         1187 +        } else if (fontpattern) {
         1188 +                if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
         1189 +                        fprintf(stderr, "error, cannot load font from pattern.\n");
         1190 +                        return NULL;
         1191 +                }
         1192 +        } else {
         1193 +                die("no font specified.");
         1194 +        }
         1195 +
         1196 +        font = ecalloc(1, sizeof(Fnt));
         1197 +        font->xfont = xfont;
         1198 +        font->pattern = pattern;
         1199 +        font->h = xfont->ascent + xfont->descent;
         1200 +        font->dpy = drw->dpy;
         1201 +
         1202 +        return font;
         1203 +}
         1204 +
         1205 +static void
         1206 +xfont_free(Fnt *font)
         1207 +{
         1208 +        if (!font)
         1209 +                return;
         1210 +        if (font->pattern)
         1211 +                FcPatternDestroy(font->pattern);
         1212 +        XftFontClose(font->dpy, font->xfont);
         1213 +        free(font);
         1214 +}
         1215 +
         1216 +Fnt*
         1217 +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
         1218 +{
         1219 +        Fnt *cur, *ret = NULL;
         1220 +        size_t i;
         1221 +
         1222 +        if (!drw || !fonts)
         1223 +                return NULL;
         1224 +
         1225 +        for (i = 1; i <= fontcount; i++) {
         1226 +                if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
         1227 +                        cur->next = ret;
         1228 +                        ret = cur;
         1229 +                }
         1230 +        }
         1231 +        return (drw->fonts = ret);
         1232 +}
         1233 +
         1234 +void
         1235 +drw_fontset_free(Fnt *font)
         1236 +{
         1237 +        if (font) {
         1238 +                drw_fontset_free(font->next);
         1239 +                xfont_free(font);
         1240 +        }
         1241 +}
         1242 +
         1243 +void
         1244 +drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
         1245 +{
         1246 +        if (!drw || !dest || !clrname)
         1247 +                return;
         1248 +
         1249 +        if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
         1250 +                               DefaultColormap(drw->dpy, drw->screen),
         1251 +                               clrname, dest))
         1252 +                die("error, cannot allocate color '%s'", clrname);
         1253 +}
         1254 +
         1255 +/* Wrapper to create color schemes. The caller has to call free(3) on the
         1256 + * returned color scheme when done using it. */
         1257 +Clr *
         1258 +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
         1259 +{
         1260 +        size_t i;
         1261 +        Clr *ret;
         1262 +
         1263 +        /* need at least two colors for a scheme */
         1264 +        if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
         1265 +                return NULL;
         1266 +
         1267 +        for (i = 0; i < clrcount; i++)
         1268 +                drw_clr_create(drw, &ret[i], clrnames[i]);
         1269 +        return ret;
         1270 +}
         1271 +
         1272 +void
         1273 +drw_setfontset(Drw *drw, Fnt *set)
         1274 +{
         1275 +        if (drw)
         1276 +                drw->fonts = set;
         1277 +}
         1278 +
         1279 +void
         1280 +drw_setscheme(Drw *drw, Clr *scm)
         1281 +{
         1282 +        if (drw)
         1283 +                drw->scheme = scm;
         1284 +}
         1285 +
         1286 +void
         1287 +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
         1288 +{
         1289 +        if (!drw || !drw->scheme)
         1290 +                return;
         1291 +        XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
         1292 +        if (filled)
         1293 +                XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
         1294 +        else
         1295 +                XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
         1296 +}
         1297 +
         1298 +int
         1299 +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
         1300 +{
         1301 +        int ty, ellipsis_x = 0;
         1302 +        unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
         1303 +        XftDraw *d = NULL;
         1304 +        Fnt *usedfont, *curfont, *nextfont;
         1305 +        int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
         1306 +        long utf8codepoint = 0;
         1307 +        const char *utf8str;
         1308 +        FcCharSet *fccharset;
         1309 +        FcPattern *fcpattern;
         1310 +        FcPattern *match;
         1311 +        XftResult result;
         1312 +        int charexists = 0, overflow = 0;
         1313 +        /* keep track of a couple codepoints for which we have no match. */
         1314 +        static unsigned int nomatches[128], ellipsis_width, invalid_width;
         1315 +        static const char invalid[] = "�";
         1316 +
         1317 +        if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
         1318 +                return 0;
         1319 +
         1320 +        if (!render) {
         1321 +                w = invert ? invert : ~invert;
         1322 +        } else {
         1323 +                XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
         1324 +                XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
         1325 +                if (w < lpad)
         1326 +                        return x + w;
         1327 +                d = XftDrawCreate(drw->dpy, drw->drawable,
         1328 +                                  DefaultVisual(drw->dpy, drw->screen),
         1329 +                                  DefaultColormap(drw->dpy, drw->screen));
         1330 +                x += lpad;
         1331 +                w -= lpad;
         1332 +        }
         1333 +
         1334 +        usedfont = drw->fonts;
         1335 +        if (!ellipsis_width && render)
         1336 +                ellipsis_width = drw_fontset_getwidth(drw, "...");
         1337 +        if (!invalid_width && render)
         1338 +                invalid_width = drw_fontset_getwidth(drw, invalid);
         1339 +        while (1) {
         1340 +                ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
         1341 +                utf8str = text;
         1342 +                nextfont = NULL;
         1343 +                while (*text) {
         1344 +                        utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
         1345 +                        for (curfont = drw->fonts; curfont; curfont = curfont->next) {
         1346 +                                charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
         1347 +                                if (charexists) {
         1348 +                                        drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
         1349 +                                        if (ew + ellipsis_width <= w) {
         1350 +                                                /* keep track where the ellipsis still fits */
         1351 +                                                ellipsis_x = x + ew;
         1352 +                                                ellipsis_w = w - ew;
         1353 +                                                ellipsis_len = utf8strlen;
         1354 +                                        }
         1355 +
         1356 +                                        if (ew + tmpw > w) {
         1357 +                                                overflow = 1;
         1358 +                                                /* called from drw_fontset_getwidth_clamp():
         1359 +                                                 * it wants the width AFTER the overflow
         1360 +                                                 */
         1361 +                                                if (!render)
         1362 +                                                        x += tmpw;
         1363 +                                                else
         1364 +                                                        utf8strlen = ellipsis_len;
         1365 +                                        } else if (curfont == usedfont) {
         1366 +                                                text += utf8charlen;
         1367 +                                                utf8strlen += utf8err ? 0 : utf8charlen;
         1368 +                                                ew += utf8err ? 0 : tmpw;
         1369 +                                        } else {
         1370 +                                                nextfont = curfont;
         1371 +                                        }
         1372 +                                        break;
         1373 +                                }
         1374 +                        }
         1375 +
         1376 +                        if (overflow || !charexists || nextfont || utf8err)
         1377 +                                break;
         1378 +                        else
         1379 +                                charexists = 0;
         1380 +                }
         1381 +
         1382 +                if (utf8strlen) {
         1383 +                        if (render) {
         1384 +                                ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
         1385 +                                XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
         1386 +                                                  usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
         1387 +                        }
         1388 +                        x += ew;
         1389 +                        w -= ew;
         1390 +                }
         1391 +                if (utf8err && (!render || invalid_width < w)) {
         1392 +                        if (render)
         1393 +                                drw_text(drw, x, y, w, h, 0, invalid, invert);
         1394 +                        x += invalid_width;
         1395 +                        w -= invalid_width;
         1396 +                }
         1397 +                if (render && overflow)
         1398 +                        drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
         1399 +
         1400 +                if (!*text || overflow) {
         1401 +                        break;
         1402 +                } else if (nextfont) {
         1403 +                        charexists = 0;
         1404 +                        usedfont = nextfont;
         1405 +                } else {
         1406 +                        /* Regardless of whether or not a fallback font is found, the
         1407 +                         * character must be drawn. */
         1408 +                        charexists = 1;
         1409 +
         1410 +                        hash = (unsigned int)utf8codepoint;
         1411 +                        hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
         1412 +                        hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
         1413 +                        h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
         1414 +                        h1 = (hash >> 17) % LENGTH(nomatches);
         1415 +                        /* avoid expensive XftFontMatch call when we know we won't find a match */
         1416 +                        if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
         1417 +                                goto no_match;
         1418 +
         1419 +                        fccharset = FcCharSetCreate();
         1420 +                        FcCharSetAddChar(fccharset, utf8codepoint);
         1421 +
         1422 +                        if (!drw->fonts->pattern) {
         1423 +                                /* Refer to the comment in xfont_create for more information. */
         1424 +                                die("the first font in the cache must be loaded from a font string.");
         1425 +                        }
         1426 +
         1427 +                        fcpattern = FcPatternDuplicate(drw->fonts->pattern);
         1428 +                        FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
         1429 +                        FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
         1430 +
         1431 +                        FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
         1432 +                        FcDefaultSubstitute(fcpattern);
         1433 +                        match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
         1434 +
         1435 +                        FcCharSetDestroy(fccharset);
         1436 +                        FcPatternDestroy(fcpattern);
         1437 +
         1438 +                        if (match) {
         1439 +                                usedfont = xfont_create(drw, NULL, match);
         1440 +                                if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
         1441 +                                        for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
         1442 +                                                ; /* NOP */
         1443 +                                        curfont->next = usedfont;
         1444 +                                } else {
         1445 +                                        xfont_free(usedfont);
         1446 +                                        nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
         1447 +no_match:
         1448 +                                        usedfont = drw->fonts;
         1449 +                                }
         1450 +                        }
         1451 +                }
         1452 +        }
         1453 +        if (d)
         1454 +                XftDrawDestroy(d);
         1455 +
         1456 +        return x + (render ? w : 0);
         1457 +}
         1458 +
         1459 +void
         1460 +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
         1461 +{
         1462 +        if (!drw)
         1463 +                return;
         1464 +
         1465 +        XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
         1466 +        XSync(drw->dpy, False);
         1467 +}
         1468 +
         1469 +unsigned int
         1470 +drw_fontset_getwidth(Drw *drw, const char *text)
         1471 +{
         1472 +        if (!drw || !drw->fonts || !text)
         1473 +                return 0;
         1474 +        return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
         1475 +}
         1476 +
         1477 +unsigned int
         1478 +drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
         1479 +{
         1480 +        unsigned int tmp = 0;
         1481 +        if (drw && drw->fonts && text && n)
         1482 +                tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
         1483 +        return MIN(n, tmp);
         1484 +}
         1485 +
         1486 +void
         1487 +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
         1488 +{
         1489 +        XGlyphInfo ext;
         1490 +
         1491 +        if (!font || !text)
         1492 +                return;
         1493 +
         1494 +        XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
         1495 +        if (w)
         1496 +                *w = ext.xOff;
         1497 +        if (h)
         1498 +                *h = font->h;
         1499 +}
         1500 +
         1501 +Cur *
         1502 +drw_cur_create(Drw *drw, int shape)
         1503 +{
         1504 +        Cur *cur;
         1505 +
         1506 +        if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
         1507 +                return NULL;
         1508 +
         1509 +        cur->cursor = XCreateFontCursor(drw->dpy, shape);
         1510 +
         1511 +        return cur;
         1512 +}
         1513 +
         1514 +void
         1515 +drw_cur_free(Drw *drw, Cur *cursor)
         1516 +{
         1517 +        if (!cursor)
         1518 +                return;
         1519 +
         1520 +        XFreeCursor(drw->dpy, cursor->cursor);
         1521 +        free(cursor);
         1522 +}
         1523 diff --git a/drw.c.rej b/drw.c.rej
         1524 new file mode 100644
         1525 index 0000000..a2390e4
         1526 --- /dev/null
         1527 +++ b/drw.c.rej
         1528 @@ -0,0 +1,13 @@
         1529 +--- drw.c
         1530 ++++ drw.c
         1531 +@@ -267,9 +271,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
         1532 +         } else {
         1533 +                 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
         1534 +                 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
         1535 +-                d = XftDrawCreate(drw->dpy, drw->drawable,
         1536 +-                                  DefaultVisual(drw->dpy, drw->screen),
         1537 +-                                  DefaultColormap(drw->dpy, drw->screen));
         1538 ++                d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
         1539 +                 x += lpad;
         1540 +                 w -= lpad;
         1541 +         }
         1542 diff --git a/drw.h b/drw.h
         1543 index fd7631b..48f2f93 100644
         1544 --- a/drw.h
         1545 +++ b/drw.h
         1546 @@ -20,6 +20,9 @@ typedef struct {
         1547          Display *dpy;
         1548          int screen;
         1549          Window root;
         1550 +        Visual *visual;
         1551 +        unsigned int depth;
         1552 +        Colormap cmap;
         1553          Drawable drawable;
         1554          GC gc;
         1555          Clr *scheme;
         1556 @@ -27,7 +30,7 @@ typedef struct {
         1557  } Drw;
         1558  
         1559  /* Drawable abstraction */
         1560 -Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
         1561 +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual*, unsigned int, Colormap);
         1562  void drw_resize(Drw *drw, unsigned int w, unsigned int h);
         1563  void drw_free(Drw *drw);
         1564  
         1565 @@ -39,8 +42,8 @@ unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int
         1566  void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
         1567  
         1568  /* Colorscheme abstraction */
         1569 -void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
         1570 -Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
         1571 +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
         1572 +Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
         1573  
         1574  /* Cursor abstraction */
         1575  Cur *drw_cur_create(Drw *drw, int shape);
         1576 diff --git a/patch/dmenu-alpha-20230110-5.2.diff b/patch/dmenu-alpha-20230110-5.2.diff
         1577 new file mode 100644
         1578 index 0000000..e3b1493
         1579 --- /dev/null
         1580 +++ b/patch/dmenu-alpha-20230110-5.2.diff
         1581 @@ -0,0 +1,293 @@
         1582 +From 4709ed81c8b8df043420ca9de016054088beb934 Mon Sep 17 00:00:00 2001
         1583 +From: Andrew Slice <edward.andrew.slice@gmail.com>
         1584 +Date: Tue, 10 Jan 2023 17:22:44 -0500
         1585 +Subject: [PATCH] Adds alpha transparency. This also fixes a crash that happens
         1586 + when using '-w' to embed dmenu in a window that has alpha transparency.
         1587 +
         1588 +Based on the original patch by Marcin Lukow <marcin@nerdy.cat>
         1589 +---
         1590 + config.def.h |  7 ++++++
         1591 + config.mk    |  2 +-
         1592 + dmenu.c      | 60 +++++++++++++++++++++++++++++++++++++++++++++++-----
         1593 + drw.c        | 26 ++++++++++++-----------
         1594 + drw.h        |  9 +++++---
         1595 + 5 files changed, 83 insertions(+), 21 deletions(-)
         1596 +
         1597 +diff --git a/config.def.h b/config.def.h
         1598 +index 1edb647..809c96e 100644
         1599 +--- a/config.def.h
         1600 ++++ b/config.def.h
         1601 +@@ -2,6 +2,7 @@
         1602 + /* Default settings; can be overriden by command line. */
         1603 + 
         1604 + static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */
         1605 ++static const unsigned int alpha = 0xff;     /* Amount of opacity. 0xff is opaque             */
         1606 + /* -fn option overrides fonts[0]; default X11 font or font set */
         1607 + static const char *fonts[] = {
         1608 +         "monospace:size=10"
         1609 +@@ -13,6 +14,12 @@ static const char *colors[SchemeLast][2] = {
         1610 +         [SchemeSel] = { "#eeeeee", "#005577" },
         1611 +         [SchemeOut] = { "#000000", "#00ffff" },
         1612 + };
         1613 ++
         1614 ++static const unsigned int alphas[SchemeLast][2] = {
         1615 ++        [SchemeNorm] = { OPAQUE, alpha },
         1616 ++        [SchemeSel] = { OPAQUE, alpha },
         1617 ++        [SchemeOut] = { OPAQUE, alpha },
         1618 ++};
         1619 + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */
         1620 + static unsigned int lines      = 0;
         1621 + 
         1622 +diff --git a/config.mk b/config.mk
         1623 +index 566348b..fa2b4fc 100644
         1624 +--- a/config.mk
         1625 ++++ b/config.mk
         1626 +@@ -21,7 +21,7 @@ FREETYPEINC = /usr/include/freetype2
         1627 + 
         1628 + # includes and libs
         1629 + INCS = -I$(X11INC) -I$(FREETYPEINC)
         1630 +-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
         1631 ++LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender
         1632 + 
         1633 + # flags
         1634 + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
         1635 +diff --git a/dmenu.c b/dmenu.c
         1636 +index 27b7a30..a20302f 100644
         1637 +--- a/dmenu.c
         1638 ++++ b/dmenu.c
         1639 +@@ -10,10 +10,12 @@
         1640 + 
         1641 + #include <X11/Xlib.h>
         1642 + #include <X11/Xatom.h>
         1643 ++#include <X11/Xproto.h>
         1644 + #include <X11/Xutil.h>
         1645 + #ifdef XINERAMA
         1646 + #include <X11/extensions/Xinerama.h>
         1647 + #endif
         1648 ++#include <X11/extensions/Xrender.h>
         1649 + #include <X11/Xft/Xft.h>
         1650 + 
         1651 + #include "drw.h"
         1652 +@@ -25,6 +27,8 @@
         1653 + #define LENGTH(X)             (sizeof X / sizeof X[0])
         1654 + #define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad)
         1655 + 
         1656 ++#define OPAQUE                0xffu
         1657 ++
         1658 + /* enums */
         1659 + enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
         1660 + 
         1661 +@@ -53,10 +57,16 @@ static XIC xic;
         1662 + static Drw *drw;
         1663 + static Clr *scheme[SchemeLast];
         1664 + 
         1665 ++static int useargb = 0;
         1666 ++static Visual *visual;
         1667 ++static int depth;
         1668 ++static Colormap cmap;
         1669 ++
         1670 + #include "config.h"
         1671 + 
         1672 + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
         1673 + static char *(*fstrstr)(const char *, const char *) = strstr;
         1674 ++static void xinitvisual();
         1675 + 
         1676 + static unsigned int
         1677 + textw_clamp(const char *str, unsigned int n)
         1678 +@@ -627,7 +637,7 @@ setup(void)
         1679 + #endif
         1680 +         /* init appearance */
         1681 +         for (j = 0; j < SchemeLast; j++)
         1682 +-                scheme[j] = drw_scm_create(drw, colors[j], 2);
         1683 ++                scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2);
         1684 + 
         1685 +         clip = XInternAtom(dpy, "CLIPBOARD",   False);
         1686 +         utf8 = XInternAtom(dpy, "UTF8_STRING", False);
         1687 +@@ -682,11 +692,13 @@ setup(void)
         1688 + 
         1689 +         /* create menu window */
         1690 +         swa.override_redirect = True;
         1691 +-        swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
         1692 ++        swa.background_pixel = 0;
         1693 ++        swa.border_pixel = 0;
         1694 ++        swa.colormap = cmap;
         1695 +         swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
         1696 +         win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
         1697 +-                            CopyFromParent, CopyFromParent, CopyFromParent,
         1698 +-                            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
         1699 ++                            depth, CopyFromParent, visual,
         1700 ++                            CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
         1701 +         XSetClassHint(dpy, win, &ch);
         1702 + 
         1703 + 
         1704 +@@ -771,7 +783,8 @@ main(int argc, char *argv[])
         1705 +         if (!XGetWindowAttributes(dpy, parentwin, &wa))
         1706 +                 die("could not get embedding window attributes: 0x%lx",
         1707 +                     parentwin);
         1708 +-        drw = drw_create(dpy, screen, root, wa.width, wa.height);
         1709 ++        xinitvisual();
         1710 ++        drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
         1711 +         if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
         1712 +                 die("no fonts could be loaded.");
         1713 +         lrpad = drw->fonts->h;
         1714 +@@ -793,3 +806,40 @@ main(int argc, char *argv[])
         1715 + 
         1716 +         return 1; /* unreachable */
         1717 + }
         1718 ++
         1719 ++void
         1720 ++xinitvisual()
         1721 ++{
         1722 ++        XVisualInfo *infos;
         1723 ++        XRenderPictFormat *fmt;
         1724 ++        int nitems;
         1725 ++        int i;
         1726 ++
         1727 ++        XVisualInfo tpl = {
         1728 ++                .screen = screen,
         1729 ++                .depth = 32,
         1730 ++                .class = TrueColor
         1731 ++        };
         1732 ++        long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
         1733 ++
         1734 ++        infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
         1735 ++        visual = NULL;
         1736 ++        for(i = 0; i < nitems; i ++) {
         1737 ++                fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
         1738 ++                if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
         1739 ++                         visual = infos[i].visual;
         1740 ++                         depth = infos[i].depth;
         1741 ++                         cmap = XCreateColormap(dpy, root, visual, AllocNone);
         1742 ++                         useargb = 1;
         1743 ++                         break;
         1744 ++                }
         1745 ++        }
         1746 ++
         1747 ++        XFree(infos);
         1748 ++
         1749 ++        if (! visual) {
         1750 ++                visual = DefaultVisual(dpy, screen);
         1751 ++                depth = DefaultDepth(dpy, screen);
         1752 ++                cmap = DefaultColormap(dpy, screen);
         1753 ++        }
         1754 ++}
         1755 +diff --git a/drw.c b/drw.c
         1756 +index a58a2b4..42700e5 100644
         1757 +--- a/drw.c
         1758 ++++ b/drw.c
         1759 +@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
         1760 + }
         1761 + 
         1762 + Drw *
         1763 +-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
         1764 ++drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
         1765 + {
         1766 +         Drw *drw = ecalloc(1, sizeof(Drw));
         1767 + 
         1768 +@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
         1769 +         drw->root = root;
         1770 +         drw->w = w;
         1771 +         drw->h = h;
         1772 +-        drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
         1773 +-        drw->gc = XCreateGC(dpy, root, 0, NULL);
         1774 ++        drw->visual = visual;
         1775 ++        drw->depth = depth;
         1776 ++        drw->cmap = cmap;
         1777 ++        drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
         1778 ++        drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
         1779 +         XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
         1780 + 
         1781 +         return drw;
         1782 +@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
         1783 +         drw->h = h;
         1784 +         if (drw->drawable)
         1785 +                 XFreePixmap(drw->dpy, drw->drawable);
         1786 +-        drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
         1787 ++        drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
         1788 + }
         1789 + 
         1790 + void
         1791 +@@ -181,21 +184,22 @@ drw_fontset_free(Fnt *font)
         1792 + }
         1793 + 
         1794 + void
         1795 +-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
         1796 ++drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
         1797 + {
         1798 +         if (!drw || !dest || !clrname)
         1799 +                 return;
         1800 + 
         1801 +-        if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
         1802 +-                               DefaultColormap(drw->dpy, drw->screen),
         1803 ++        if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
         1804 +                                clrname, dest))
         1805 +                 die("error, cannot allocate color '%s'", clrname);
         1806 ++
         1807 ++        dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
         1808 + }
         1809 + 
         1810 + /* Wrapper to create color schemes. The caller has to call free(3) on the
         1811 +  * returned color scheme when done using it. */
         1812 + Clr *
         1813 +-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
         1814 ++drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
         1815 + {
         1816 +         size_t i;
         1817 +         Clr *ret;
         1818 +@@ -205,7 +209,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
         1819 +                 return NULL;
         1820 + 
         1821 +         for (i = 0; i < clrcount; i++)
         1822 +-                drw_clr_create(drw, &ret[i], clrnames[i]);
         1823 ++                drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
         1824 +         return ret;
         1825 + }
         1826 + 
         1827 +@@ -263,9 +267,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
         1828 +         } else {
         1829 +                 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
         1830 +                 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
         1831 +-                d = XftDrawCreate(drw->dpy, drw->drawable,
         1832 +-                                  DefaultVisual(drw->dpy, drw->screen),
         1833 +-                                  DefaultColormap(drw->dpy, drw->screen));
         1834 ++                d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
         1835 +                 x += lpad;
         1836 +                 w -= lpad;
         1837 +         }
         1838 +diff --git a/drw.h b/drw.h
         1839 +index fd7631b..48f2f93 100644
         1840 +--- a/drw.h
         1841 ++++ b/drw.h
         1842 +@@ -20,6 +20,9 @@ typedef struct {
         1843 +         Display *dpy;
         1844 +         int screen;
         1845 +         Window root;
         1846 ++        Visual *visual;
         1847 ++        unsigned int depth;
         1848 ++        Colormap cmap;
         1849 +         Drawable drawable;
         1850 +         GC gc;
         1851 +         Clr *scheme;
         1852 +@@ -27,7 +30,7 @@ typedef struct {
         1853 + } Drw;
         1854 + 
         1855 + /* Drawable abstraction */
         1856 +-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
         1857 ++Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual*, unsigned int, Colormap);
         1858 + void drw_resize(Drw *drw, unsigned int w, unsigned int h);
         1859 + void drw_free(Drw *drw);
         1860 + 
         1861 +@@ -39,8 +42,8 @@ unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int
         1862 + void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
         1863 + 
         1864 + /* Colorscheme abstraction */
         1865 +-void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
         1866 +-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
         1867 ++void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
         1868 ++Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
         1869 + 
         1870 + /* Cursor abstraction */
         1871 + Cur *drw_cur_create(Drw *drw, int shape);
         1872 +-- 
         1873 +2.37.4
         1874 +