Skip to content

Commit 8cc6b1f

Browse files
committed
dmenu 5.3
1 parent 58fbd4b commit 8cc6b1f

File tree

10 files changed

+145
-107
lines changed

10 files changed

+145
-107
lines changed

suckless/dmenu/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ MIT/X Consortium License
88
© 2009 Markus Schnalke <[email protected]>
99
© 2009 Evan Gates <[email protected]>
1010
© 2010-2012 Connor Lane Smith <[email protected]>
11-
© 2014-2020 Hiltjo Posthuma <[email protected]>
11+
© 2014-2022 Hiltjo Posthuma <[email protected]>
1212
© 2015-2019 Quentin Rameau <[email protected]>
1313

1414
Permission is hereby granted, free of charge, to any person obtaining a

suckless/dmenu/Makefile

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@ include config.mk
66
SRC = drw.c dmenu.c stest.c util.c
77
OBJ = $(SRC:.c=.o)
88

9-
all: options dmenu stest
10-
11-
options:
12-
@echo dmenu build options:
13-
@echo "CFLAGS = $(CFLAGS)"
14-
@echo "LDFLAGS = $(LDFLAGS)"
15-
@echo "CC = $(CC)"
9+
all: dmenu stest
1610

1711
.c.o:
1812
$(CC) -c $(CFLAGS) $<
@@ -61,4 +55,4 @@ uninstall:
6155
$(DESTDIR)$(MANPREFIX)/man1/dmenu.1\
6256
$(DESTDIR)$(MANPREFIX)/man1/stest.1
6357

64-
.PHONY: all options clean dist install uninstall
58+
.PHONY: all clean dist install uninstall

suckless/dmenu/config.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# dmenu version
2-
VERSION = 5.0
2+
VERSION = 5.3
33

44
# paths
55
PREFIX = /usr/local
@@ -17,6 +17,7 @@ FREETYPELIBS = -lfontconfig -lXft
1717
FREETYPEINC = /usr/include/freetype2
1818
# OpenBSD (uncomment)
1919
#FREETYPEINC = $(X11INC)/freetype2
20+
#MANPREFIX = ${PREFIX}/man
2021

2122
# includes and libs
2223
INCS = -I$(X11INC) -I$(FREETYPEINC)

suckless/dmenu/dmenu.c

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
/* macros */
2323
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
2424
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
25-
#define LENGTH(X) (sizeof X / sizeof X[0])
2625
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
2726

2827
/* enums */
@@ -58,6 +57,13 @@ static Clr *scheme[SchemeLast];
5857
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
5958
static char *(*fstrstr)(const char *, const char *) = strstr;
6059

60+
static unsigned int
61+
textw_clamp(const char *str, unsigned int n)
62+
{
63+
unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
64+
return MIN(w, n);
65+
}
66+
6167
static void
6268
appenditem(struct item *item, struct item **list, struct item **last)
6369
{
@@ -82,10 +88,10 @@ calcoffsets(void)
8288
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
8389
/* calculate which items will begin the next page and previous page */
8490
for (i = 0, next = curr; next; next = next->right)
85-
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
91+
if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
8692
break;
8793
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
88-
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
94+
if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
8995
break;
9096
}
9197

@@ -97,19 +103,29 @@ cleanup(void)
97103
XUngrabKey(dpy, AnyKey, AnyModifier, root);
98104
for (i = 0; i < SchemeLast; i++)
99105
free(scheme[i]);
106+
for (i = 0; items && items[i].text; ++i)
107+
free(items[i].text);
108+
free(items);
100109
drw_free(drw);
101110
XSync(dpy, False);
102111
XCloseDisplay(dpy);
103112
}
104113

105114
static char *
106-
cistrstr(const char *s, const char *sub)
115+
cistrstr(const char *h, const char *n)
107116
{
108-
size_t len;
117+
size_t i;
118+
119+
if (!n[0])
120+
return (char *)h;
109121

110-
for (len = strlen(sub); *s; s++)
111-
if (!strncasecmp(s, sub, len))
112-
return (char *)s;
122+
for (; *h; ++h) {
123+
for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
124+
tolower((unsigned char)h[i]); ++i)
125+
;
126+
if (n[i] == '\0')
127+
return (char *)h;
128+
}
113129
return NULL;
114130
}
115131

@@ -165,7 +181,7 @@ drawmenu(void)
165181
}
166182
x += w;
167183
for (item = curr; item != next; item = item->right)
168-
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
184+
x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
169185
if (next) {
170186
w = TEXTW(">");
171187
drw_setscheme(drw, scheme[SchemeNorm]);
@@ -225,7 +241,7 @@ match(void)
225241
/* separate input text into tokens to be matched individually */
226242
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
227243
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
228-
die("cannot realloc %u bytes:", tokn * sizeof *tokv);
244+
die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
229245
len = tokc ? strlen(tokv[0]) : 0;
230246

231247
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
@@ -307,19 +323,19 @@ movewordedge(int dir)
307323
static void
308324
keypress(XKeyEvent *ev)
309325
{
310-
char buf[32];
326+
char buf[64];
311327
int len;
312-
KeySym ksym;
328+
KeySym ksym = NoSymbol;
313329
Status status;
314330

315331
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
316332
switch (status) {
317333
default: /* XLookupNone, XBufferOverflow */
318334
return;
319-
case XLookupChars:
335+
case XLookupChars: /* composed string from input method */
320336
goto insert;
321337
case XLookupKeySym:
322-
case XLookupBoth:
338+
case XLookupBoth: /* a KeySym and a string are returned: use keysym */
323339
break;
324340
}
325341

@@ -360,9 +376,11 @@ keypress(XKeyEvent *ev)
360376
utf8, utf8, win, CurrentTime);
361377
return;
362378
case XK_Left:
379+
case XK_KP_Left:
363380
movewordedge(-1);
364381
goto draw;
365382
case XK_Right:
383+
case XK_KP_Right:
366384
movewordedge(+1);
367385
goto draw;
368386
case XK_Return:
@@ -396,10 +414,11 @@ keypress(XKeyEvent *ev)
396414
switch(ksym) {
397415
default:
398416
insert:
399-
if (!iscntrl(*buf))
417+
if (!iscntrl((unsigned char)*buf))
400418
insert(buf, len);
401419
break;
402420
case XK_Delete:
421+
case XK_KP_Delete:
403422
if (text[cursor] == '\0')
404423
return;
405424
cursor = nextrune(+1);
@@ -410,6 +429,7 @@ keypress(XKeyEvent *ev)
410429
insert(NULL, nextrune(-1) - cursor);
411430
break;
412431
case XK_End:
432+
case XK_KP_End:
413433
if (text[cursor] != '\0') {
414434
cursor = strlen(text);
415435
break;
@@ -429,6 +449,7 @@ keypress(XKeyEvent *ev)
429449
cleanup();
430450
exit(1);
431451
case XK_Home:
452+
case XK_KP_Home:
432453
if (sel == matches) {
433454
cursor = 0;
434455
break;
@@ -437,6 +458,7 @@ keypress(XKeyEvent *ev)
437458
calcoffsets();
438459
break;
439460
case XK_Left:
461+
case XK_KP_Left:
440462
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
441463
cursor = nextrune(-1);
442464
break;
@@ -445,18 +467,21 @@ keypress(XKeyEvent *ev)
445467
return;
446468
/* fallthrough */
447469
case XK_Up:
470+
case XK_KP_Up:
448471
if (sel && sel->left && (sel = sel->left)->right == curr) {
449472
curr = prev;
450473
calcoffsets();
451474
}
452475
break;
453476
case XK_Next:
477+
case XK_KP_Next:
454478
if (!next)
455479
return;
456480
sel = curr = next;
457481
calcoffsets();
458482
break;
459483
case XK_Prior:
484+
case XK_KP_Prior:
460485
if (!prev)
461486
return;
462487
sel = curr = prev;
@@ -473,6 +498,7 @@ keypress(XKeyEvent *ev)
473498
sel->out = 1;
474499
break;
475500
case XK_Right:
501+
case XK_KP_Right:
476502
if (text[cursor] != '\0') {
477503
cursor = nextrune(+1);
478504
break;
@@ -481,6 +507,7 @@ keypress(XKeyEvent *ev)
481507
return;
482508
/* fallthrough */
483509
case XK_Down:
510+
case XK_KP_Down:
484511
if (sel && sel->right && (sel = sel->right) == next) {
485512
curr = next;
486513
calcoffsets();
@@ -489,9 +516,9 @@ keypress(XKeyEvent *ev)
489516
case XK_Tab:
490517
if (!sel)
491518
return;
492-
strncpy(text, sel->text, sizeof text - 1);
493-
text[sizeof text - 1] = '\0';
494-
cursor = strlen(text);
519+
cursor = strnlen(sel->text, sizeof text - 1);
520+
memcpy(text, sel->text, cursor);
521+
text[cursor] = '\0';
495522
match();
496523
break;
497524
}
@@ -521,29 +548,27 @@ paste(void)
521548
static void
522549
readstdin(void)
523550
{
524-
char buf[sizeof text], *p;
525-
size_t i, imax = 0, size = 0;
526-
unsigned int tmpmax = 0;
551+
char *line = NULL;
552+
size_t i, itemsiz = 0, linesiz = 0;
553+
ssize_t len;
527554

528555
/* read each line from stdin and add it to the item list */
529-
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
530-
if (i + 1 >= size / sizeof *items)
531-
if (!(items = realloc(items, (size += BUFSIZ))))
532-
die("cannot realloc %u bytes:", size);
533-
if ((p = strchr(buf, '\n')))
534-
*p = '\0';
535-
if (!(items[i].text = strdup(buf)))
536-
die("cannot strdup %u bytes:", strlen(buf) + 1);
537-
items[i].out = 0;
538-
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
539-
if (tmpmax > inputw) {
540-
inputw = tmpmax;
541-
imax = i;
556+
for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) {
557+
if (i + 1 >= itemsiz) {
558+
itemsiz += 256;
559+
if (!(items = realloc(items, itemsiz * sizeof(*items))))
560+
die("cannot realloc %zu bytes:", itemsiz * sizeof(*items));
542561
}
562+
if (line[len - 1] == '\n')
563+
line[len - 1] = '\0';
564+
if (!(items[i].text = strdup(line)))
565+
die("strdup:");
566+
567+
items[i].out = 0;
543568
}
569+
free(line);
544570
if (items)
545571
items[i].text = NULL;
546-
inputw = items ? TEXTW(items[imax].text) : 0;
547572
lines = MIN(lines, i);
548573
}
549574

@@ -634,7 +659,7 @@ setup(void)
634659
/* no focused window is on screen, so use pointer location instead */
635660
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
636661
for (i = 0; i < n; i++)
637-
if (INTERSECT(x, y, 1, 1, info[i]))
662+
if (INTERSECT(x, y, 1, 1, info[i]) != 0)
638663
break;
639664

640665
x = info[i].x_org;
@@ -652,14 +677,14 @@ setup(void)
652677
mw = wa.width;
653678
}
654679
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
655-
inputw = MIN(inputw, mw/3);
680+
inputw = mw / 3; /* input width: ~33% of monitor width */
656681
match();
657682

658683
/* create menu window */
659684
swa.override_redirect = True;
660685
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
661686
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
662-
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
687+
win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
663688
CopyFromParent, CopyFromParent, CopyFromParent,
664689
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
665690
XSetClassHint(dpy, win, &ch);
@@ -674,6 +699,7 @@ setup(void)
674699

675700
XMapRaised(dpy, win);
676701
if (embed) {
702+
XReparentWindow(dpy, win, parentwin, x, y);
677703
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
678704
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
679705
for (i = 0; i < du && dws[i] != win; ++i)
@@ -689,9 +715,8 @@ setup(void)
689715
static void
690716
usage(void)
691717
{
692-
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
693-
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
694-
exit(1);
718+
die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
719+
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");
695720
}
696721

697722
int

suckless/dmenu/dmenu_path

100644100755
File mode changed.

0 commit comments

Comments
 (0)