diff options
| -rw-r--r-- | LICENSE | 30 | ||||
| -rw-r--r-- | config.def.h | 29 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | dmenu.c | 108 | ||||
| -rw-r--r-- | drw.c | 14 | ||||
| -rw-r--r-- | util.c | 23 |
6 files changed, 138 insertions, 68 deletions
@@ -0,0 +1,30 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe <anselm@garbe.ca> +© 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com> +© 2006-2007 Michał Janeczek <janeczek@gmail.com> +© 2007 Kris Maglione <jg@suckless.org> +© 2009 Gottox <gottox@s01.de> +© 2009 Markus Schnalke <meillo@marmaro.de> +© 2009 Evan Gates <evan.gates@gmail.com> +© 2010-2012 Connor Lane Smith <cls@lubutu.com> +© 2014-2022 Hiltjo Posthuma <hiltjo@codemadness.org> +© 2015-2019 Quentin Rameau <quinq@fifth.space> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..94330f1 --- /dev/null +++ b/config.def.h @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +/* Default settings; can be overriden by command line. */ + +static int centered = 1; +static int min_width = 500; +static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static int draw_input = 1; /* -noi option; if 0, the input will not be drawn by default */ +/* -fn option overrides fonts[0]; default X11 font or font set */ +static const char *fonts[] = { + "monospace:size=10" +}; +static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#ebdbb2", "#282828" }, + [SchemeSel] = { "#ebdbb2", "#928374" }, + [SchemeOut] = { "#ebdbb2", "#8ec07c" }, +}; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 22; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; + +/* Size of the window border */ +static unsigned int border_width = 2; @@ -1,5 +1,5 @@ # dmenu version -VERSION = 5.1 +VERSION = 5.2 # paths PREFIX = /usr/local @@ -157,30 +157,32 @@ drawmenu(void) { unsigned int curpos; struct item *item; - int x = 0, y = 0, w; + int x = 0, y = 0, w = 0; 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); + x = drw_text(drw, x, 0, ((!draw_input) ? mw : 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); - curpos = TEXTW(text) - TEXTW(&text[cursor]); - if ((curpos += lrpad / 2 - 1) < w) { + if (draw_input) { + w = (lines > 0 || !matches) ? mw - x : inputw; drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); + drw_text(drw, x, 0, w, bh, lrpad / 2, text, 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); + } } if (lines > 0) { /* draw vertical list */ for (item = curr; item != next; item = item->right) - drawitem(item, x - promptw, y += bh, mw); + drawitem(item, !draw_input ? x - mw : x - promptw, y += bh, mw); } else if (matches) { /* draw horizontal list */ x += inputw; @@ -188,8 +190,8 @@ drawmenu(void) if (curr->left) { drw_setscheme(drw, scheme[SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); + x += w; } - x += w; for (item = curr; item != next; item = item->right) x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">"))); if (next) { @@ -368,16 +370,19 @@ keypress(XKeyEvent *ev) case XK_p: ksym = XK_Up; break; case XK_k: /* delete right */ - text[cursor] = '\0'; - match(); + if (draw_input) { + text[cursor] = '\0'; + match(); + } break; case XK_u: /* delete left */ - insert(NULL, 0 - cursor); + if (draw_input) + insert(NULL, 0 - cursor); break; case XK_w: /* delete word */ - while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]) && draw_input) insert(NULL, nextrune(-1) - cursor); - while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]) && draw_input) insert(NULL, nextrune(-1) - cursor); break; case XK_y: /* paste selection */ @@ -424,23 +429,23 @@ keypress(XKeyEvent *ev) switch(ksym) { default: insert: - if (!iscntrl((unsigned char)*buf)) + if (!iscntrl((unsigned char)*buf) && draw_input) insert(buf, len); break; case XK_Delete: case XK_KP_Delete: - if (text[cursor] == '\0') + if (text[cursor] == '\0' || !draw_input) return; cursor = nextrune(+1); /* fallthrough */ case XK_BackSpace: - if (cursor == 0) + if (cursor == 0 || !draw_input) return; insert(NULL, nextrune(-1) - cursor); break; case XK_End: case XK_KP_End: - if (text[cursor] != '\0') { + if (text[cursor] != '\0' && draw_input) { cursor = strlen(text); break; } @@ -524,11 +529,11 @@ insert: } break; case XK_Tab: - if (!sel) + if (!sel || !draw_input) 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; } @@ -558,18 +563,18 @@ paste(void) static void readstdin(void) { - char buf[sizeof text], *p; - size_t i, size = 0; + char *line = NULL; + size_t i, junk, size = 0; + ssize_t len; /* 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 %zu bytes:", size); - if ((p = strchr(buf, '\n'))) - *p = '\0'; - if (!(items[i].text = strdup(buf))) - die("cannot strdup %zu bytes:", strlen(buf) + 1); + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + items[i].text = line; items[i].out = 0; } if (items) @@ -668,9 +673,16 @@ setup(void) if (INTERSECT(x, y, 1, 1, info[i]) != 0) break; - mw = MIN(MAX(max_textw() + promptw, 100), info[i].width); - x = info[i].x_org + ((info[i].width - mw) / 2); - y = info[i].y_org + ((info[i].height - mh) / 2); + 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); + } else { + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; + } + XFree(info); } else #endif @@ -678,11 +690,19 @@ setup(void) if (!XGetWindowAttributes(dpy, parentwin, &wa)) die("could not get embedding window attributes: 0x%lx", parentwin); - mw = MIN(MAX(max_textw() + promptw, 100), wa.width); - x = (wa.width - mw) / 2; - y = (wa.height - mh) / 2; + + if (centered) { + mw = MIN(MAX(max_textw() + promptw, min_width), wa.width); + x = (wa.width - mw) / 2; + y = (wa.height - mh) / 2; + } else { + x = 0; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; + } } - inputw = mw / 3; /* input width: ~33% of monitor width */ + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + inputw = !draw_input ? 0 : mw / 3; /* input width: ~33% of monitor width */ match(); /* create menu window */ @@ -692,7 +712,8 @@ setup(void) win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); - XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); + if (border_width) + XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); XSetClassHint(dpy, win, &ch); @@ -720,9 +741,8 @@ setup(void) static void usage(void) { - fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); - exit(1); + die("usage: dmenu [-bfiv] [-noi] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); } int @@ -740,6 +760,8 @@ 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], "-noi")) /* no input field. intended to be used with a prompt */ + draw_input = 0; else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ fstrncmp = strncasecmp; fstrstr = cistrstr; @@ -764,6 +786,8 @@ main(int argc, char *argv[]) colors[SchemeSel][ColFg] = 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 usage(); @@ -133,19 +133,6 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) die("no font specified."); } - /* Do not allow using color fonts. This is a workaround for a BadLength - * error from Xft with color glyphs. Modelled on the Xterm workaround. See - * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 - * https://lists.suckless.org/dev/1701/30932.html - * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 - * and lots more all over the internet. - */ - FcBool iscol; - if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { - XftFontClose(drw->dpy, xfont); - return NULL; - } - font = ecalloc(1, sizeof(Fnt)); font->xfont = xfont; font->pattern = pattern; @@ -368,7 +355,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp fcpattern = FcPatternDuplicate(drw->fonts->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); - FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); @@ -6,18 +6,9 @@ #include "util.h" -void * -ecalloc(size_t nmemb, size_t size) -{ - void *p; - - if (!(p = calloc(nmemb, size))) - die("calloc:"); - return p; -} - void -die(const char *fmt, ...) { +die(const char *fmt, ...) +{ va_list ap; va_start(ap, fmt); @@ -33,3 +24,13 @@ die(const char *fmt, ...) { exit(1); } + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} |
