diff options
Diffstat (limited to 'dmenu.c')
-rw-r--r-- | dmenu.c | 180 |
1 files changed, 160 insertions, 20 deletions
@@ -26,10 +26,11 @@ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) /* enums */ -enum { SchemeNorm, SchemeSel, SchemeOut, SchemeBorder, SchemeLast }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ struct item { char *text; + unsigned int width; struct item *left, *right; int out; }; @@ -54,7 +55,7 @@ static Drw *drw; static Clr *scheme[SchemeLast]; /* Temporary arrays to allow overriding xresources values */ -static char *colortemp[5]; +static char *colortemp[4]; static char *tempfonts; #include "config.h" @@ -105,7 +106,7 @@ max_textw(void) { int len = 0; for (struct item *item = items; item && item->text; item++) - len = MAX(TEXTW(item->text), len); + len = MAX(item->width, len); return len; } @@ -542,6 +543,142 @@ draw: } static void +buttonpress(XEvent *e) +{ + struct item *item; + XButtonPressedEvent *ev = &e->xbutton; + int x = 0, y = 0, h = bh, w; + + if (ev->window != win) + return; + + /* right-click: exit */ + if (ev->button == Button3) + exit(1); + + if (prompt && *prompt) + x += promptw; + + /* input field */ + w = (lines > 0 || !matches) ? mw - x : inputw; + + /* left-click on input: clear input, + * NOTE: if there is no left-arrow the space for < is reserved so + * add that to the input width */ + if (ev->button == Button1 && + ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + + ((!prev || !curr->left) ? TEXTW("<") : 0)) || + (lines > 0 && ev->y >= y && ev->y <= y + h))) { + insert(NULL, -cursor); + drawmenu(); + return; + } + /* middle-mouse click: paste selection */ + if (ev->button == Button2) { + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + drawmenu(); + return; + } + /* scroll up */ + if (ev->button == Button4 && prev) { + sel = curr = prev; + calcoffsets(); + drawmenu(); + return; + } + /* scroll down */ + if (ev->button == Button5 && next) { + sel = curr = next; + calcoffsets(); + drawmenu(); + return; + } + if (ev->button != Button1) + return; + if (ev->state & ~ControlMask) + return; + if (lines > 0) { + /* vertical list: (ctrl)left-click on item */ + w = mw - x; + for (item = curr; item != next; item = item->right) { + y += h; + if (ev->y >= y && ev->y <= (y + h)) { + puts(item->text); + if (!(ev->state & ControlMask)) + exit(0); + sel = item; + if (sel) { + sel->out = 1; + drawmenu(); + } + return; + } + } + } else if (matches) { + /* left-click on left arrow */ + x += inputw; + w = TEXTW("<"); + if (prev && curr->left) { + if (ev->x >= x && ev->x <= x + w) { + sel = curr = prev; + calcoffsets(); + drawmenu(); + return; + } + } + /* horizontal list: (ctrl)left-click on item */ + 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) { + puts(item->text); + if (!(ev->state & ControlMask)) + exit(0); + sel = item; + if (sel) { + sel->out = 1; + drawmenu(); + } + return; + } + } + /* left-click on right arrow */ + w = TEXTW(">"); + x = mw - w; + if (next && ev->x >= x && ev->x <= x + w) { + sel = curr = next; + calcoffsets(); + drawmenu(); + return; + } + } +} + +static void +motionevent(XButtonEvent *ev) +{ + struct item *it; + int xy, ev_xy; + + if (ev->window != win || matches == 0) + return; + + xy = lines > 0 ? bh : inputw + promptw + TEXTW("<"); + ev_xy = lines > 0 ? ev->y : ev->x; + for (it = curr; it && it != next; it = it->right) { + int wh = lines > 0 ? bh : textw_clamp(it->text, mw - xy - TEXTW(">")); + if (ev_xy >= xy && ev_xy < (xy + wh)) { + sel = it; + calcoffsets(); + drawmenu(); + break; + } + xy += wh; + } +} + +static void paste(void) { char *p, *q; @@ -577,6 +714,7 @@ readstdin(void) line[len - 1] = '\0'; if (!(items[i].text = strdup(line))) die("strdup:"); + items[i].width = TEXTW(line); items[i].out = 0; } @@ -600,6 +738,12 @@ run(void) break; cleanup(); exit(1); + case ButtonPress: + buttonpress(&ev); + break; + case MotionNotify: + motionevent(&ev.xbutton); + break; case Expose: if (ev.xexpose.count == 0) drw_map(drw, win, 0, 0, mw, mh); @@ -685,7 +829,7 @@ setup(void) if (centered) { mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width); x = info[i].x_org + ((info[i].width - mw) / 2); - y = info[i].y_org + ((info[i].height - mh) / 2); + y = info[i].y_org + ((info[i].height - mh) / menu_height_ratio); } else { x = info[i].x_org; y = info[i].y_org + (topbar ? 0 : info[i].height - mh); @@ -708,21 +852,23 @@ setup(void) x = 0; y = topbar ? 0 : wa.height - mh; mw = wa.width; - } + } } - + 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; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | + ButtonPressMask | PointerMotionMask; win = XCreateWindow(dpy, parentwin, x, y - (topbar ? 0 : border_width * 2), mw - border_width * 2, mh, border_width, - CopyFromParent, CopyFromParent, CopyFromParent, - CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + CopyFromParent, CopyFromParent, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); if (border_width) - XSetWindowBorder(dpy, win, scheme[SchemeBorder][ColFg].pixel); + XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); + XSetClassHint(dpy, win, &ch); /* input methods */ @@ -784,10 +930,6 @@ readxresources(void) { colors[SchemeSel][ColFg] = strdup(xval.addr); else colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); - if (XrmGetResource(xdb, "dmenu.border", "*", &type, &xval)) - colors[SchemeBorder][ColFg] = strdup(xval.addr); - else - colors[SchemeBorder][ColFg] = strdup(colors[SchemeBorder][ColFg]); XrmDestroyDatabase(xdb); } @@ -856,15 +998,13 @@ main(int argc, char *argv[]) if ( tempfonts ) fonts[0] = strdup(tempfonts); if ( colortemp[0]) - colors[SchemeNorm][ColBg] = strdup(colortemp[0]); + colors[SchemeNorm][ColBg] = strdup(colortemp[0]); if ( colortemp[1]) - colors[SchemeNorm][ColFg] = strdup(colortemp[1]); + colors[SchemeNorm][ColFg] = strdup(colortemp[1]); if ( colortemp[2]) - colors[SchemeSel][ColBg] = strdup(colortemp[2]); + colors[SchemeSel][ColBg] = strdup(colortemp[2]); if ( colortemp[3]) - colors[SchemeSel][ColFg] = strdup(colortemp[3]); - if ( colortemp[4]) - colors[SchemeBorder][ColFg] = strdup(colortemp[4]); + colors[SchemeSel][ColFg] = strdup(colortemp[3]); if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts))) die("no fonts could be loaded."); |