summaryrefslogtreecommitdiff
path: root/dmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'dmenu.c')
-rw-r--r--dmenu.c207
1 files changed, 88 insertions, 119 deletions
diff --git a/dmenu.c b/dmenu.c
index d304e3a..33c07e5 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -24,8 +24,6 @@
/* macros */
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
-#define BOOL_INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
- && MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
@@ -36,7 +34,7 @@ enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight,
struct item {
char *text;
- char *text_output;
+ char *text_output;
struct item *left, *right;
int out;
double distance;
@@ -44,9 +42,8 @@ struct item {
static char text[BUFSIZ] = "";
static char *embed;
-static char separator;
-static int separator_greedy;
-static int separator_reverse;
+static char separator, separator_reverse;
+static char * (*sepchr)(const char *, int);
static int bh, mw, mh;
static int inputw = 0, promptw, passwd = 0;
static int lrpad; /* sum of left and right padding */
@@ -66,7 +63,7 @@ static Drw *drw;
static Clr *scheme[SchemeLast];
/* Temporary arrays to allow overriding xresources values */
-static char *colortemp[4];
+static char *colortemp[8];
static char *tempfonts;
#include "config.h"
@@ -74,6 +71,13 @@ static char *tempfonts;
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
+static unsigned int
+textw_clamp(const char *str, unsigned int n)
+{
+ unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
+ return MIN(w, n);
+}
+
static void
appenditem(struct item *item, struct item **list, struct item **last)
{
@@ -98,10 +102,10 @@ calcoffsets(void)
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
/* calculate which items will begin the next page and previous page */
for (i = 0, next = curr; next; next = next->right)
- if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
+ if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
break;
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
- if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
+ if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
break;
}
@@ -122,6 +126,9 @@ cleanup(void)
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for (i = 0; i < SchemeLast; i++)
free(scheme[i]);
+ for (i = 0; items && items[i].text; ++i)
+ free(separator_reverse ? items[i].text_output : items[i].text);
+ free(items);
drw_free(drw);
XSync(dpy, False);
XCloseDisplay(dpy);
@@ -159,19 +166,17 @@ drawhighlights(struct item *item, int x, int y, int maxw)
? SchemeSelHighlight
: SchemeNormHighlight]);
for (i = 0, highlight = item->text; *highlight && text[i];) {
- if (!fstrncmp(&(*highlight), &text[i], 1)) {
+ if (!fstrncmp(&text[i], highlight, 1)) {
+ c = highlight[1];
+ highlight[1] = '\0';
+
/* get indentation */
- c = *highlight;
- *highlight = '\0';
indent = TEXTW(item->text);
- *highlight = c;
/* highlight character */
- c = highlight[1];
- highlight[1] = '\0';
drw_text(
drw,
- x + indent - (lrpad / 2),
+ x + indent - lrpad,
y,
MIN(maxw - indent, TEXTW(highlight) - lrpad),
bh, 0, highlight, 0
@@ -220,7 +225,7 @@ drawmenu(void)
drw_setscheme(drw, scheme[SchemeNorm]);
if (passwd) {
censort = ecalloc(1, sizeof(text));
- memset(censort, '.', strlen(text));
+ memset(censort, '*', strlen(text));
drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0);
free(censort);
} else drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
@@ -245,7 +250,7 @@ drawmenu(void)
}
x += w;
for (item = curr; item != next; item = item->right)
- x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
+ x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
if (next) {
w = TEXTW(">");
drw_setscheme(drw, scheme[SchemeNorm]);
@@ -390,7 +395,7 @@ match(void)
/* separate input text into tokens to be matched individually */
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
- die("cannot realloc %u bytes:", tokn * sizeof *tokv);
+ die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
len = tokc ? strlen(tokv[0]) : 0;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
@@ -577,7 +582,7 @@ keypress(XKeyEvent *ev)
switch(ksym) {
default:
insert:
- if (!iscntrl(*buf))
+ if (!iscntrl((unsigned char)*buf))
insert(buf, len);
break;
case XK_Delete:
@@ -679,9 +684,9 @@ insert:
case XK_Tab:
if (!sel)
return;
- strncpy(text, sel->text, sizeof text - 1);
- text[sizeof text - 1] = '\0';
- cursor = strlen(text);
+ cursor = strnlen(sel->text, sizeof text - 1);
+ memcpy(text, sel->text, cursor);
+ text[cursor] = '\0';
match();
break;
}
@@ -744,11 +749,8 @@ buttonpress(XEvent *e)
}
if (ev->button != Button1)
return;
- /* disabled below, needs to be fixed */
- /*
if (ev->state & ~ControlMask)
return;
- */
if (lines > 0) {
/* vertical list: (ctrl)left-click on item */
w = mw - x;
@@ -807,40 +809,6 @@ buttonpress(XEvent *e)
}
static void
-mousemove(XEvent *e)
-{
- struct item *item;
- XPointerMovedEvent *ev = &e->xmotion;
- int x = 0, y = 0, h = bh, w;
-
- if (lines > 0) {
- w = mw - x;
- for (item = curr; item != next; item = item->right) {
- y += h;
- if (ev->y >= y && ev->y <= (y + h)) {
- sel = item;
- calcoffsets();
- drawmenu();
- return;
- }
- }
- } else if (matches) {
- x += inputw;
- w = TEXTW("<");
- for (item = curr; item != next; item = item->right) {
- x += w;
- w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
- if (ev->x >= x && ev->x <= x + w) {
- sel = item;
- calcoffsets();
- drawmenu();
- return;
- }
- }
- }
-}
-
-static void
paste(void)
{
char *p, *q;
@@ -861,26 +829,25 @@ paste(void)
static void
readstdin(void)
{
- char buf[sizeof text], *p;
- size_t i, imax = 0, size = 0;
- unsigned int tmpmax = 0;
- if(passwd){
- inputw = lines = 0;
- return;
- }
+ char *p, *line = NULL;
+ size_t i, junk, size = 0;
+ ssize_t len;
+ if(passwd) {
+ inputw = lines = 0;
+ return;
+ }
/* read each line from stdin and add it to the item list */
- for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
+ for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) {
if (i + 1 >= size / sizeof *items)
if (!(items = realloc(items, (size += BUFSIZ))))
- die("cannot realloc %u bytes:", size);
- if ((p = strchr(buf, '\n')))
- *p = '\0';
- if (!(items[i].text = strdup(buf)))
- die("cannot strdup %u bytes:", strlen(buf) + 1);
- if (separator && (p = separator_greedy ?
- strrchr(items[i].text, separator) : strchr(items[i].text, separator))) {
+ die("cannot realloc %zu bytes:", size);
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ items[i].text = line;
+
+ if (separator && (p = sepchr(items[i].text, separator)) != NULL) {
*p = '\0';
items[i].text_output = ++p;
} else {
@@ -891,16 +858,11 @@ readstdin(void)
items[i].text = items[i].text_output;
items[i].text_output = p;
}
+
items[i].out = 0;
- drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
- if (tmpmax > inputw) {
- inputw = tmpmax;
- imax = i;
- }
}
if (items)
items[i].text = NULL;
- inputw = items ? TEXTW(items[imax].text) : 0;
lines = MIN(lines, i);
}
@@ -921,9 +883,6 @@ run(void)
case ButtonPress:
buttonpress(&ev);
break;
- case MotionNotify:
- mousemove(&ev);
- break;
case Expose:
if (ev.xexpose.count == 0)
drw_map(drw, win, 0, 0, mw, mh);
@@ -1004,7 +963,7 @@ setup(void)
/* no focused window is on screen, so use pointer location instead */
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
for (i = 0; i < n; i++)
- if (BOOL_INTERSECT(x, y, 1, 1, info[i]))
+ if (INTERSECT(x, y, 1, 1, info[i]) != 0)
break;
if (centered) {
@@ -1035,14 +994,15 @@ setup(void)
mw = wa.width;
}
}
- inputw = MIN(inputw, mw/3);
+ promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
+ inputw = mw / 3; /* input width: ~33% of monitor width */
match();
/* create menu window */
swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask |
- ButtonPressMask | PointerMotionMask;
+ ButtonPressMask;
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
@@ -1075,11 +1035,10 @@ setup(void)
static void
usage(void)
{
- fputs("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
- " [-nb color] [-nf color] [-sb color] [-sf color] [-bw width]\n"
- " [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n"
- " [-d separator] [-D separator]\n", stderr);
- exit(1);
+ die("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
+ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n"
+ " [-nhb color] [-nhf color] [-shb color] [-shf color]\n"
+ " [-d separator] [-D separator] [-h height]");
}
void
@@ -1112,22 +1071,22 @@ readxresources(void) {
colors[SchemeSel][ColFg] = strdup(xval.addr);
else
colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]);
+ if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval))
+ colors[SchemeNormHighlight][ColBg] = strdup(xval.addr);
+ else
+ colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]);
+ if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval))
+ colors[SchemeNormHighlight][ColFg] = strdup(xval.addr);
+ else
+ colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]);
if (XrmGetResource(xdb, "dmenu.selhibackground", "*", &type, &xval))
colors[SchemeSelHighlight][ColBg] = strdup(xval.addr);
else
- colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColBg]);
+ colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]);
if (XrmGetResource(xdb, "dmenu.selhiforeground", "*", &type, &xval))
colors[SchemeSelHighlight][ColFg] = strdup(xval.addr);
else
colors[SchemeSelHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]);
- if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval))
- colors[SchemeNormHighlight][ColBg] = strdup(xval.addr);
- else
- colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeNorm][ColBg]);
- if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval))
- colors[SchemeNormHighlight][ColFg] = strdup(xval.addr);
- else
- colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeNorm][ColFg]);
XrmDestroyDatabase(xdb);
}
@@ -1148,14 +1107,14 @@ main(int argc, char *argv[])
topbar = 0;
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
fast = 1;
- else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */
- centered = 1;
- else if (!strcmp(argv[i], "-F")) /* grabs keyboard before reading stdin */
- fuzzy = 1;
+ else if (!strcmp(argv[i], "-F")) /* toggles fuzzy matching */
+ fuzzy = fuzzy ? 0 : 1;
+ else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */
+ centered = 1;
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
fstrncmp = strncasecmp;
fstrstr = cistrstr;
- } else if (!strcmp(argv[i], "-P")) /* is the input a password */
+ } else if (!strcmp(argv[i], "-P")) /* is the input a password */
passwd = 1;
else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */
reject_no_match = 1;
@@ -1182,22 +1141,24 @@ main(int argc, char *argv[])
colortemp[2] = argv[++i];
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
colortemp[3] = argv[++i];
- else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */
- colors[SchemeNormHighlight][ColBg] = argv[++i];
- else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */
- colors[SchemeNormHighlight][ColFg] = argv[++i];
- else if (!strcmp(argv[i], "-shb")) /* selected hi background color */
- colors[SchemeSelHighlight][ColBg] = argv[++i];
- else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */
- colors[SchemeSelHighlight][ColFg] = argv[++i];
+ else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */
+ colortemp[4] = argv[++i];
+ else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */
+ colortemp[5] = argv[++i];
+ else if (!strcmp(argv[i], "-shb")) /* selected hi background color */
+ colortemp[6] = argv[++i];
+ else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */
+ colortemp[7] = argv[++i];
else if (!strcmp(argv[i], "-w")) /* embedding window id */
embed = argv[++i];
+ else if (!strcmp(argv[i], "-bw"))
+ border_width = atoi(argv[++i]); /* border width */
else if (!strcmp(argv[i], "-d") || /* field separator */
- (separator_greedy = !strcmp(argv[i], "-D"))) {
- separator = argv[++i][0];
- separator_reverse = argv[i][1] == '|';
- } else if (!strcmp(argv[i], "-bw"))
- border_width = atoi(argv[++i]); /* border width */
+ !strcmp(argv[i], "-D")) {
+ sepchr = argv[i][1] == 'D' ? strrchr : strchr;
+ separator = argv[++i][0];
+ separator_reverse = argv[i][1] == '|';
+ }
else
usage();
@@ -1225,6 +1186,14 @@ main(int argc, char *argv[])
colors[SchemeSel][ColBg] = strdup(colortemp[2]);
if ( colortemp[3])
colors[SchemeSel][ColFg] = strdup(colortemp[3]);
+ if ( colortemp[4])
+ colors[SchemeNormHighlight][ColBg] = strdup(colortemp[4]);
+ if ( colortemp[5])
+ colors[SchemeNormHighlight][ColFg] = strdup(colortemp[5]);
+ if ( colortemp[6])
+ colors[SchemeSelHighlight][ColBg] = strdup(colortemp[6]);
+ if ( colortemp[7])
+ colors[SchemeSelHighlight][ColFg] = strdup(colortemp[7]);
if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts)))
die("no fonts could be loaded.");