sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | 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 +