diff options
| author | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-11 10:45:46 -0500 |
|---|---|---|
| committer | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-11 10:45:46 -0500 |
| commit | 2341d8444599f7bd350d6e12d2f48fe4cecc819d (patch) | |
| tree | 7a1bd6d796fb7ff3d4ce55c3ee5163ada5873c73 /core/dmenu/dmenu.c | |
| parent | 0408cb4803e0b2c82affb16e2eac8dfd73895343 (diff) | |
feat: enlarge dmenu input and add dwm power binds
Diffstat (limited to 'core/dmenu/dmenu.c')
| -rw-r--r-- | core/dmenu/dmenu.c | 331 |
1 files changed, 146 insertions, 185 deletions
diff --git a/core/dmenu/dmenu.c b/core/dmenu/dmenu.c index 54a14e2..ebc2801 100644 --- a/core/dmenu/dmenu.c +++ b/core/dmenu/dmenu.c @@ -41,7 +41,8 @@ struct item { static char text[BUFSIZ] = ""; static char *embed; static int bh, mw, mh; -static int inputw = 0, promptw; +static int ih; +static int promptw; static int lrpad; /* sum of left and right padding */ static size_t cursor; static struct item *items = NULL; @@ -60,7 +61,9 @@ static Clr *scheme[SchemeLast]; #include "../accent.h" static ColorShm *accentshm; static char accentcol[8] = "#005577"; +static Clr accent[2]; static const double opacity = 0.85; +static const unsigned int border_width = 3; static void initaccent(void); static void updateaccent(void); @@ -68,14 +71,18 @@ static void setopacity(Window w, double opacity); #include "config.h" -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) +static int +fuzzy(const char *text, const char *pattern) { - unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad; - return MIN(w, n); + for (; *pattern; pattern++) { + while (*text && tolower((unsigned char)*text) != + tolower((unsigned char)*pattern)) + text++; + if (!*text) + return 0; + text++; + } + return 1; } static void @@ -94,19 +101,15 @@ appenditem(struct item *item, struct item **list, struct item **last) static void calcoffsets(void) { - int i, n; - - if (lines > 0) - n = lines * bh; - else - 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 : textw_clamp(next->text, n)) > n) - break; - for (i = 0, prev = curr; prev && prev->left; prev = prev->left) - if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n) - break; + int i, n; + + n = lines * bh; + for (i = 0, next = curr; next; next = next->right) + if ((i += bh) > n) + break; + for (i = 0, prev = curr; prev && prev->left; prev = prev->left) + if ((i += bh) > n) + break; } static void @@ -128,8 +131,13 @@ cleanup(void) static void updateaccent(void) { - if (readaccent(&accentshm, accentcol)) + if (readaccent(&accentshm, accentcol)) { drw_clr_create(drw, &scheme[SchemeSel][ColBg], accentcol); + drw_clr_create(drw, &accent[ColFg], accentcol); + drw_clr_create(drw, &accent[ColBg], accentcol); + if (win) + XSetWindowBorder(dpy, win, accent[ColFg].pixel); + } } static void @@ -137,24 +145,6 @@ initaccent(void) { updateaccent(); } -static char * -cistrstr(const char *h, const char *n) -{ - size_t i; - - if (!n[0]) - return (char *)h; - - for (; *h; ++h) { - for (i = 0; n[i] && tolower((unsigned char)n[i]) == - tolower((unsigned char)h[i]); ++i) - ; - if (n[i] == '\0') - return (char *)h; - } - return NULL; -} - static int drawitem(struct item *item, int x, int y, int w) { @@ -171,50 +161,41 @@ drawitem(struct item *item, int x, int y, int w) static void drawmenu(void) { - unsigned int curpos; - struct item *item; - int x = 0, y = 0, w; + unsigned int curpos; + struct item *item; + int x = 0, y = 0, w; - drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, 0, 0, mw, mh, 1, 1); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); - if (prompt && *prompt) { - drw_setscheme(drw, scheme[SchemeSel]); - x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); - } - /* draw input field */ - w = (lines > 0 || !matches) ? mw - x : inputw; - drw_setscheme(drw, scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); + if (prompt && *prompt) { + drw_setscheme(drw, scheme[SchemeSel]); + x = drw_text(drw, x, 0, promptw, ih, lrpad / 2, prompt, 0); + } + /* draw input field */ + w = mw - x; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, ih, lrpad / 2, text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { + int cy = (ih - bh) / 2 + 2; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x + curpos, cy, 2, bh - 4, 1, 0); + } - curpos = TEXTW(text) - TEXTW(&text[cursor]); - if ((curpos += lrpad / 2 - 1) < w) { - drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); - } + drw_setscheme(drw, accent); + drw_rect(drw, 0, ih - 1, mw, 1, 1, 1); - if (lines > 0) { - /* draw vertical list */ - for (item = curr; item != next; item = item->right) - drawitem(item, x, y += bh, mw - x); - } else if (matches) { - /* draw horizontal list */ - x += inputw; - w = TEXTW("<"); - if (curr->left) { - drw_setscheme(drw, scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); - } - x += w; - for (item = curr; item != next; item = item->right) - x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">"))); - if (next) { - w = TEXTW(">"); - drw_setscheme(drw, scheme[SchemeNorm]); - drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); - } - } - drw_map(drw, win, 0, 0, mw, mh); + y = ih; + for (item = curr; item != next; item = item->right) { + drawitem(item, x, y, mw - x); + drw_setscheme(drw, accent); + drw_rect(drw, x, y + bh - 1, mw - x, 1, 1, 1); + y += bh; + } + + drw_map(drw, win, 0, 0, mw, mh); } static void @@ -264,55 +245,32 @@ grabkeyboard(void) static void match(void) { - static char **tokv = NULL; - static int tokn = 0; - - char buf[sizeof text], *s; - int i, tokc = 0; - size_t len, textsize; - struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; - - strcpy(buf, text); - /* 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 %zu bytes:", tokn * sizeof *tokv); - len = tokc ? strlen(tokv[0]) : 0; - - matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; - textsize = strlen(text) + 1; - for (item = items; item && item->text; item++) { - for (i = 0; i < tokc; i++) - if (!fstrstr(item->text, tokv[i])) - break; - if (i != tokc) /* not all tokens match */ - continue; - /* exact matches go first, then prefixes, then substrings */ - if (!tokc || !fstrncmp(text, item->text, textsize)) - appenditem(item, &matches, &matchend); - else if (!fstrncmp(tokv[0], item->text, len)) - appenditem(item, &lprefix, &prefixend); - else - appenditem(item, &lsubstr, &substrend); - } - if (lprefix) { - if (matches) { - matchend->right = lprefix; - lprefix->left = matchend; - } else - matches = lprefix; - matchend = prefixend; - } - if (lsubstr) { - if (matches) { - matchend->right = lsubstr; - lsubstr->left = matchend; - } else - matches = lsubstr; - matchend = substrend; - } - curr = sel = matches; - calcoffsets(); + static char **tokv = NULL; + static int tokn = 0; + + char buf[sizeof text], *s; + int i, tokc = 0; + struct item *item; + + strcpy(buf, text); + /* separate input text into tokens to be matched individually */ + for (s = strtok(buf, " "); s; s = strtok(NULL, " ")) { + if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) + die("cannot realloc %zu bytes:", tokn * sizeof *tokv); + tokv[tokc - 1] = s; + } + + matches = matchend = NULL; + for (item = items; item && item->text; item++) { + for (i = 0; i < tokc; i++) + if (!fuzzy(item->text, tokv[i])) + break; + if (i != tokc) + continue; + appenditem(item, &matches, &matchend); + } + curr = sel = matches; + calcoffsets(); } static void @@ -675,67 +633,71 @@ setup(void) int a, di, n, area = 0; #endif /* init appearance */ - for (j = 0; j < SchemeLast; j++) - scheme[j] = drw_scm_create(drw, colors[j], 2); + for (j = 0; j < SchemeLast; j++) + scheme[j] = drw_scm_create(drw, colors[j], 2); + drw_clr_create(drw, &accent[ColFg], accentcol); + drw_clr_create(drw, &accent[ColBg], accentcol); clip = XInternAtom(dpy, "CLIPBOARD", False); utf8 = XInternAtom(dpy, "UTF8_STRING", False); - /* calculate menu geometry */ - bh = drw->fonts->h + 2; - lines = MAX(lines, 0); - mh = (lines + 1) * bh; + /* calculate menu geometry */ + bh = drw->fonts->h + 2; + ih = (bh * 3) / 2; #ifdef XINERAMA - i = 0; - if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { - XGetInputFocus(dpy, &w, &di); - if (mon >= 0 && mon < n) - i = mon; - else if (w != root && w != PointerRoot && w != None) { - /* find top-level window containing current input focus */ - do { - if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) - XFree(dws); - } while (w != root && w != pw); - /* find xinerama screen with which the window intersects most */ - if (XGetWindowAttributes(dpy, pw, &wa)) - for (j = 0; j < n; j++) - if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { - area = a; - i = j; - } - } - /* 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 (INTERSECT(x, y, 1, 1, info[i]) != 0) - break; - - x = info[i].x_org; - y = info[i].y_org + (topbar ? 0 : info[i].height - mh); - mw = info[i].width; - XFree(info); - } else + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); + if (mon >= 0 && mon < n) + i = mon; + else if (w != root && w != PointerRoot && w != None) { + do { + if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) + XFree(dws); + } while (w != root && w != pw); + if (XGetWindowAttributes(dpy, pw, &wa)) + for (j = 0; j < n; j++) + if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { + area = a; + i = j; + } + } + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + for (i = 0; i < n; i++) + if (INTERSECT(x, y, 1, 1, info[i]) != 0) + break; + + mw = info[i].width / 2; + int max_lines = (info[i].height - ih) / bh; + lines = lines ? MIN(lines, max_lines) : MIN(20, max_lines); + mh = ih + lines * bh; + x = info[i].x_org + (info[i].width - mw) / 2; + y = info[i].y_org + (info[i].height - mh) / 2; + XFree(info); + } else #endif - { - if (!XGetWindowAttributes(dpy, parentwin, &wa)) - die("could not get embedding window attributes: 0x%lx", - parentwin); - 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(); + { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + mw = wa.width / 2; + int max_lines = (wa.height - ih) / bh; + lines = lines ? MIN(lines, max_lines) : MIN(20, max_lines); + mh = ih + lines * bh; + x = (wa.width - mw) / 2; + y = (wa.height - mh) / 2; + } + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + match(); /* create menu window */ swa.override_redirect = True; swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - win = XCreateWindow(dpy, root, x, y, mw, mh, 0, - CopyFromParent, CopyFromParent, CopyFromParent, - CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + swa.border_pixel = accent[ColFg].pixel; + win = XCreateWindow(dpy, root, x, y, mw, mh, border_width, + CopyFromParent, CopyFromParent, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask | CWBorderPixel, &swa); XSetClassHint(dpy, win, &ch); /* input methods */ @@ -782,12 +744,11 @@ main(int argc, char *argv[]) exit(0); } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ topbar = 0; - else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ - fast = 1; - else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ - fstrncmp = strncasecmp; - fstrstr = cistrstr; - } else if (i + 1 == argc) + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + /* no-op: matching is case-insensitive */ + } else if (i + 1 == argc) usage(); /* these options take one argument */ else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ |
