diff options
author | Franklyn Tackitt | 2015-06-10 09:04:50 -0700 |
---|---|---|
committer | Franklyn Tackitt | 2015-06-10 09:04:50 -0700 |
commit | f1a8b6b7e7c4c2f675bd1f775cf647743b53c6ff (patch) | |
tree | 6d91ecf14c14729ae1c6d5b8d64267f6940b99bf | |
download | aur-f1a8b6b7e7c4c2f675bd1f775cf647743b53c6ff.tar.gz |
Initial Import
-rw-r--r-- | .SRCINFO | 31 | ||||
-rw-r--r-- | PKGBUILD | 43 | ||||
-rw-r--r-- | break-fix.diff | 23 | ||||
-rw-r--r-- | dmenu-4.5-fuzzy-fixed.diff | 94 | ||||
-rw-r--r-- | dmenu-4.5-height-fixed.diff | 84 | ||||
-rw-r--r-- | dmenu-4.5-history-fixed.diff | 216 | ||||
-rw-r--r-- | dmenu-4.5-mouse-support.diff | 143 | ||||
-rw-r--r-- | dmenu-4.5-xft.diff | 418 |
8 files changed, 1052 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..f11d6db9fbfb --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,31 @@ +pkgbase = dmenu-xft-mouse-height-fuzzy-history + pkgdesc = Dynamic X menu - with xft, mouse, height, history, and fuzzy search support + pkgver = 4.5 + pkgrel = 5 + url = http://tools.suckless.org/dmenu/ + arch = i686 + arch = x86_64 + license = MIT + depends = sh + depends = libxinerama + depends = libxft + provides = dmenu + conflicts = dmenu + conflicts = dmenu2 + source = http://dl.suckless.org/tools/dmenu-4.5.tar.gz + source = dmenu-4.5-xft.diff + source = break-fix.diff + source = dmenu-4.5-history-fixed.diff + source = dmenu-4.5-fuzzy-fixed.diff + source = dmenu-4.5-mouse-support.diff + source = dmenu-4.5-height-fixed.diff + md5sums = 9c46169ed703732ec52ed946c27d84b4 + md5sums = 0c73d595eb78f159bea83f33bba15e80 + md5sums = 6921f9d8aabb53f22adcbf5630dff6b8 + md5sums = 8541735789d9810d7020fdba62b72296 + md5sums = 71fc82b76c45499fcd46b3754407f59d + md5sums = eeec3e11ff68f27ebbc3133ad6549f56 + md5sums = 53b286e8bd76d9225f365673fafd6083 + +pkgname = dmenu-xft-mouse-height-fuzzy-history + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..14c3d338f494 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,43 @@ +# Maintainer: Franklyn Tackitt +pkgname=dmenu-xft-mouse-height-fuzzy-history +pkgver=4.5 +pkgrel=5 +pkgdesc="Dynamic X menu - with xft, mouse, height, history, and fuzzy search support" +url="http://tools.suckless.org/dmenu/" +arch=('i686' 'x86_64') +license=('MIT') +depends=('sh' 'libxinerama' 'libxft') +conflicts=('dmenu' 'dmenu2') +provides=('dmenu') +patches=(dmenu-4.5-xft.diff + break-fix.diff + dmenu-4.5-history-fixed.diff + dmenu-4.5-fuzzy-fixed.diff + dmenu-4.5-mouse-support.diff + dmenu-4.5-height-fixed.diff) +source=(http://dl.suckless.org/tools/dmenu-$pkgver.tar.gz "${patches[@]}") +md5sums=('9c46169ed703732ec52ed946c27d84b4' + '0c73d595eb78f159bea83f33bba15e80' + '6921f9d8aabb53f22adcbf5630dff6b8' + '8541735789d9810d7020fdba62b72296' + '71fc82b76c45499fcd46b3754407f59d' + 'eeec3e11ff68f27ebbc3133ad6549f56' + '53b286e8bd76d9225f365673fafd6083') +prepare() { + cd $srcdir/dmenu-$pkgver + for patch in "${patches[@]}"; do + echo "Patching $patch" + patch -p1 < "../${patch}" + done +} +build() { + cd $srcdir/dmenu-$pkgver + make +} +package() +{ + cd "$srcdir/dmenu-$pkgver" + make DESTDIR=$pkgdir PREFIX=/usr install + install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" + +} diff --git a/break-fix.diff b/break-fix.diff new file mode 100644 index 000000000000..989ee6707961 --- /dev/null +++ b/break-fix.diff @@ -0,0 +1,23 @@ +diff -upr dmenu-4.5-xft/dmenu.c dmenu-4.5-break/dmenu.c +--- dmenu-4.5-xft/dmenu.c 2014-05-04 17:32:10.896300286 -0600 ++++ dmenu-4.5-break/dmenu.c 2014-05-04 17:31:41.406300227 -0600 +@@ -337,8 +337,9 @@ keypress(XKeyEvent *ev) { + sel = matchend; + break; + case XK_Escape: +- ret = EXIT_FAILURE; +- running = False; ++ ret = EXIT_FAILURE; ++ running = False; ++ break; + case XK_Home: + if(sel == matches) { + cursor = 0; +@@ -378,6 +379,7 @@ keypress(XKeyEvent *ev) { + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + ret = EXIT_SUCCESS; + running = False; ++ break; + case XK_Right: + if(text[cursor] != '\0') { + cursor = nextrune(+1); diff --git a/dmenu-4.5-fuzzy-fixed.diff b/dmenu-4.5-fuzzy-fixed.diff new file mode 100644 index 000000000000..2db2cf2b026d --- /dev/null +++ b/dmenu-4.5-fuzzy-fixed.diff @@ -0,0 +1,94 @@ +diff -rupN orig/dmenu.c new/dmenu.c +--- orig/dmenu.c 2015-02-03 11:21:10.802786099 -0700 ++++ new/dmenu.c 2015-02-03 11:22:45.321029644 -0700 +@@ -34,6 +34,9 @@ static void grabkeyboard(void); + static void insert(const char *str, ssize_t n); + static void keypress(XKeyEvent *ev); + static void match(void); ++static void match_fuzzy(void); ++static void match_tokens(void); ++static char *strchri(const char *s, int c); + static size_t nextrune(int inc); + static void paste(void); + static void readitems(void); +@@ -64,12 +67,14 @@ static Item *matches, *matchend; + static Item *prev, *curr, *next, *sel; + static Window win; + static XIC xic; ++static Bool fuzzy; + + static char *histfile = NULL; + static Item *histitems, *histend; + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; + static char *(*fstrstr)(const char *, const char *) = strstr; ++static char *(*fstrchr)(const char *, const int) = strchr; + + int + main(int argc, char *argv[]) { +@@ -86,9 +91,12 @@ main(int argc, char *argv[]) { + topbar = False; + else if(!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = True; ++ else if(!strcmp(argv[i], "-z")) /* enable fuzzy matching */ ++ fuzzy = True; + else if(!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + fstrncmp = strncasecmp; + fstrstr = cistrstr; ++ fstrchr = strchri; + } + else if(i+1 == argc) + usage(); +@@ -464,8 +472,52 @@ keypress(XKeyEvent *ev) { + drawmenu(); + } + ++char * ++strchri(const char *s, int c) { ++ char *u, *l; ++ if(!isalpha(c)) return strchr(s, c); ++ if(isupper(c)) { ++ u = strchr(s, c); ++ l = strchr(s, tolower(c)); ++ } ++ else { ++ l = strchr(s, c); ++ u = strchr(s, toupper(c)); ++ } ++ ++ if(u && l) return u < l ? u : l; ++ return u == NULL ? l : u; ++} ++ + void + match(void) { ++ if(fuzzy) match_fuzzy(); ++ else match_tokens(); ++} ++ ++void ++match_fuzzy(void) { ++ int i; ++ size_t len; ++ Item *item; ++ ++ char *pos; ++ ++ len = strlen(text); ++ ++ matches = matchend = NULL; ++ for(item = items; item && item->text; item++) { ++ i = 0; ++ for(pos = fstrchr(item->text, text[i]); pos && text[i]; i++, pos = fstrchr(pos+1, text[i])); ++ if(i == len) appenditem(item, &matches, &matchend); ++ } ++ ++ curr = sel = matches; ++ calcoffsets(); ++} ++ ++void ++match_tokens(void) { + static char **tokv = NULL; + static int tokn = 0; + diff --git a/dmenu-4.5-height-fixed.diff b/dmenu-4.5-height-fixed.diff new file mode 100644 index 000000000000..8186a90f3668 --- /dev/null +++ b/dmenu-4.5-height-fixed.diff @@ -0,0 +1,84 @@ +diff -rupN orig/dmenu.1 new/dmenu.1 +--- orig/dmenu.1 2015-02-03 11:24:25.218280503 -0700 ++++ new/dmenu.1 2015-02-03 11:24:34.434303318 -0700 +@@ -8,6 +8,8 @@ dmenu \- dynamic menu + .RB [ \-i ] + .RB [ \-l + .IR lines ] ++.RB [ \-h ++.IR height ] + .RB [ \-p + .IR prompt ] + .RB [ \-fn +@@ -51,6 +53,9 @@ dmenu matches menu items case insensitiv + .BI \-l " lines" + dmenu lists items vertically, with the given number of lines. + .TP ++.BI \-h " height" ++defines the height of the bar in pixels. ++.TP + .BI \-p " prompt" + defines the prompt to be displayed to the left of the input field. + .TP +diff -rupN orig/dmenu.c new/dmenu.c +--- orig/dmenu.c 2015-02-03 11:24:25.218280503 -0700 ++++ new/dmenu.c 2015-02-03 11:25:32.430445657 -0700 +@@ -55,7 +55,7 @@ static const char *normbgcolor = "#22222 + static const char *normfgcolor = "#bbbbbb"; + static const char *selbgcolor = "#005577"; + static const char *selfgcolor = "#eeeeee"; +-static unsigned int lines = 0; ++static unsigned int lines, line_height = 0; + static ColorSet *normcol; + static ColorSet *selcol; + static Atom clip, utf8; +@@ -104,6 +104,8 @@ main(int argc, char *argv[]) { + /* these options take one argument */ + else if(!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); ++ else if(!strcmp(argv[i], "-h")) /* minimum height of single line */ ++ line_height = atoi(argv[++i]); + else if(!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ + prompt = argv[++i]; + else if(!strcmp(argv[i], "-fn")) /* font or font set */ +@@ -260,8 +262,8 @@ drawmenu(void) { + /* draw input field */ + dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; + drawtext(dc, text, normcol); +- if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w) +- drawrect(dc, curpos, 2, 1, dc->h - 4, True, normcol->FG); ++ if((curpos = textnw(dc, text, cursor) + dc->font.height/2) < dc->w) ++ drawrect(dc, curpos, (dc->h - dc->font.height)/2 + 1, 1, dc->font.height -1, True, normcol->FG); + + if(lines > 0) { + /* draw vertical list */ +@@ -800,7 +802,7 @@ setup(void) { + utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); + + /* calculate menu geometry */ +- bh = dc->font.height + 2; ++ bh = (line_height > dc->font.height + 2) ? line_height : dc->font.height + 2; + lines = MAX(lines, 0); + mh = (lines + 1) * bh; + #ifdef XINERAMA +@@ -869,7 +871,7 @@ setup(void) { + + void + usage(void) { +- fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n" ++ fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-h height] [-p prompt] [-fn font]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-hist histfile] [-v]\n", stderr); + exit(EXIT_FAILURE); + } +diff -rupN orig/draw.c new/draw.c +--- orig/draw.c 2015-02-03 11:24:25.219280505 -0700 ++++ new/draw.c 2015-02-03 11:24:34.435303320 -0700 +@@ -39,7 +39,7 @@ drawtext(DC *dc, const char *text, Color + void + drawtextn(DC *dc, const char *text, size_t n, ColorSet *col) { + int x = dc->x + dc->font.height/2; +- int y = dc->y + dc->font.ascent+1; ++ int y = dc->y + dc->font.ascent + (dc->h - dc->font.height)/2; + + XSetForeground(dc->dpy, dc->gc, col->FG); + if(dc->font.xft_font) { diff --git a/dmenu-4.5-history-fixed.diff b/dmenu-4.5-history-fixed.diff new file mode 100644 index 000000000000..4cc660b1334d --- /dev/null +++ b/dmenu-4.5-history-fixed.diff @@ -0,0 +1,216 @@ +diff -rupN without/dmenu.1 with/dmenu.1 +--- without/dmenu.1 2015-02-03 11:15:59.416937469 -0700 ++++ with/dmenu.1 2015-02-03 11:16:13.160976522 -0700 +@@ -20,6 +20,8 @@ dmenu \- dynamic menu + .IR color ] + .RB [ \-sf + .IR color ] ++.RB [ \-hist ++.IR "<filename>" ] + .RB [ \-v ] + .P + .BR dmenu_run " ..." +@@ -70,6 +72,9 @@ defines the selected background color. + .BI \-sf " color" + defines the selected foreground color. + .TP ++.BI \-hist " <histfile>" ++the file to use for history ++.TP + .B \-v + prints version information to stdout, then exits. + .SH USAGE +diff -rupN without/dmenu.c with/dmenu.c +--- without/dmenu.c 2015-02-03 11:15:59.416937469 -0700 ++++ with/dmenu.c 2015-02-03 11:19:01.935443821 -0700 +@@ -36,7 +36,7 @@ static void keypress(XKeyEvent *ev); + static void match(void); + static size_t nextrune(int inc); + static void paste(void); +-static void readstdin(void); ++static void readitems(void); + static void run(void); + static void setup(void); + static void usage(void); +@@ -65,6 +65,9 @@ static Item *prev, *curr, *next, *sel; + static Window win; + static XIC xic; + ++static char *histfile = NULL; ++static Item *histitems, *histend; ++ + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; + static char *(*fstrstr)(const char *, const char *) = strstr; + +@@ -104,6 +107,8 @@ main(int argc, char *argv[]) { + selbgcolor = argv[++i]; + else if(!strcmp(argv[i], "-sf")) /* selected foreground color */ + selfgcolor = argv[++i]; ++ else if(!strcmp(argv[i], "-hist")) ++ histfile = argv[++i]; + else + usage(); + +@@ -114,10 +119,10 @@ main(int argc, char *argv[]) { + + if(fast) { + grabkeyboard(); +- readstdin(); ++ readitems(); + } + else { +- readstdin(); ++ readitems(); + grabkeyboard(); + } + setup(); +@@ -127,6 +132,59 @@ main(int argc, char *argv[]) { + return ret; + } + ++static int ++writehistory(char *command) { ++ FILE *f; ++ Item *histitem; ++ char *histline; ++ char *histcmd; ++ int currcnt = 1; ++ int histcnt; ++ ++ if(!histfile || strlen(command) <= 0) ++ return 0; ++ ++ if((f = fopen(histfile, "w"))) { ++ /* get the current count of previous runs for this command */ ++ for(histitem = histitems; histitem && histitem->text; histitem=histitem->right) { ++ histline = strdup(histitem->text); ++ histcmd = strsep(&histline, "\t"); ++ if(strcmp(command, histcmd) == 0) { ++ currcnt = atoi(strsep(&histline, "\t")) + 1; ++ } ++ } ++ ++ /* loop through history printing those with more runs */ ++ for(histitem = histitems; histitem && histitem->text; histitem=histitem->right) { ++ histline = strdup(histitem->text); ++ histcmd = strsep(&histline, "\t"); ++ histcnt = atoi(strsep(&histline, "\t")); ++ if(histcnt > currcnt) { ++ fprintf(f, "%s", histitem->text); ++ } else { ++ break; ++ } ++ } ++ ++ /* print this command now so it's the first in line with this run count */ ++ /* reducing the count by 1 here to keep the next comparison loop simple */ ++ fprintf(f, "%s\t%d\n", command, currcnt--); ++ ++ /* print all the rest except this command's old line */ ++ for(; histitem && histitem->text; histitem=histitem->right) { ++ histline = strdup(histitem->text); ++ histcmd = strsep(&histline, "\t"); ++ histcnt = atoi(strsep(&histline, "\t")); ++ if(histcnt < currcnt || strcmp(command, histcmd) != 0) ++ fprintf(f, "%s", histitem->text); ++ } ++ fclose(f); ++ return 1; ++ } ++ ++ return 0; ++} ++ + void + appenditem(Item *item, Item **list, Item **last) { + if(*last) +@@ -378,6 +436,7 @@ keypress(XKeyEvent *ev) { + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + ret = EXIT_SUCCESS; ++ writehistory( (sel == NULL) ? text : sel->text); + running = False; + break; + case XK_Right: +@@ -484,26 +543,60 @@ paste(void) { + } + + void +-readstdin(void) { +- char buf[sizeof text], *p, *maxstr = NULL; +- size_t i, max = 0, size = 0; ++readitems(void) { ++ char buf[sizeof text], *p, *maxstr = NULL, *histline, *histcmd; ++ size_t i = 0, j = 0, k = 0, max = 0, size = 0; ++ FILE *f; ++ Bool listed; ++ Item *histitem; ++ histitems = histend = NULL; ++ ++ if(histfile && (f = fopen(histfile, "r"))) { ++ for(; fgets(buf, sizeof buf, f); i++) { ++ histitem = malloc(sizeof *histitem); ++ histitem->text = strdup(buf); ++ appenditem(histitem, &histitems, &histend); ++ if(i+1 >= size / sizeof *items) ++ if(!(items = realloc(items, (size += BUFSIZ)))) ++ eprintf("cannot realloc %u bytes:", size); ++ if((p = strchr(buf, '\n'))) ++ *p = '\0'; ++ histline = strdup(buf); ++ histcmd = strsep(&histline, "\t"); ++ if(!(items[i].text = strdup(histcmd))) ++ eprintf("cannot strdup %u bytes:", strlen(histcmd)+1); ++ if(strlen(items[i].text) > max) ++ max = strlen(maxstr = items[i].text); ++ } ++ fclose(f); ++ } + + /* read each line from stdin and add it to the item list */ +- for(i = 0; fgets(buf, sizeof buf, stdin); i++) { +- if(i+1 >= size / sizeof *items) +- if(!(items = realloc(items, (size += BUFSIZ)))) +- eprintf("cannot realloc %u bytes:", size); ++ for(j = i; fgets(buf, sizeof buf, stdin); j++) { + if((p = strchr(buf, '\n'))) + *p = '\0'; +- if(!(items[i].text = strdup(buf))) +- eprintf("cannot strdup %u bytes:", strlen(buf)+1); +- if(strlen(items[i].text) > max) +- max = strlen(maxstr = items[i].text); ++ listed = False; ++ for(k = 0; k < i; k++) { ++ if(strcmp(buf, items[k].text) == 0) { ++ listed = True; ++ j--; ++ break; ++ } ++ } ++ if(!listed) { ++ if(j+1 >= size / sizeof *items) ++ if(!(items = realloc(items, (size += BUFSIZ)))) ++ eprintf("cannot realloc %u bytes:", size); ++ if(!(items[j].text = strdup(buf))) ++ eprintf("cannot strdup %u bytes:", strlen(buf)+1); ++ if(strlen(items[j].text) > max) ++ max = strlen(maxstr = items[j].text); ++ } + } + if(items) +- items[i].text = NULL; ++ items[j].text = NULL; + inputw = maxstr ? textw(dc, maxstr) : 0; +- lines = MIN(lines, i); ++ lines = MIN(lines, j); + } + + void +@@ -617,6 +710,6 @@ setup(void) { + void + usage(void) { + fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n" +- " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); ++ " [-nb color] [-nf color] [-sb color] [-sf color] [-hist histfile] [-v]\n", stderr); + exit(EXIT_FAILURE); + } diff --git a/dmenu-4.5-mouse-support.diff b/dmenu-4.5-mouse-support.diff new file mode 100644 index 000000000000..d5bb4de2fc8e --- /dev/null +++ b/dmenu-4.5-mouse-support.diff @@ -0,0 +1,143 @@ +diff --git a/dmenu.c b/dmenu.c +index 3962801..a75bf80 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -25,6 +25,7 @@ struct Item { + }; + + static void appenditem(Item *item, Item **list, Item **last); ++static void buttonpress(XEvent *e); + static void calcoffsets(void); + static char *cistrstr(const char *s, const char *sub); + static void drawmenu(void); +@@ -388,6 +390,109 @@ keypress(XKeyEvent *ev) { + } + + void ++buttonpress(XEvent *e) { ++ int curpos; ++ Item *item; ++ XButtonPressedEvent *ev = &e->xbutton; ++ ++ if(ev->window != win) ++ return; ++ ++ /* right-click: exit */ ++ if(ev->button == Button3) ++ exit(EXIT_FAILURE); ++ ++ dc->x = 0; ++ dc->y = 0; ++ dc->h = bh; ++ ++ if(prompt && *prompt) { ++ dc->w = promptw; ++ dc->x = dc->w; ++ } ++ /* input field */ ++ dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; ++ if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w); ++ ++ /* 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 <= dc->x + dc->w + ++ ((!prev || !curr->left) ? textw(dc, "<") : 0)) || ++ (lines > 0 && ev->y >= dc->y && ev->y <= dc->y + dc->h))) { ++ insert(NULL, 0 - cursor); ++ drawmenu(); ++ return; ++ } ++ /* middle-mouse click: paste selection */ ++ if(ev->button == Button2) { ++ XConvertSelection(dc->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(lines > 0) { ++ /* vertical list: left-click on item */ ++ dc->w = mw - dc->x; ++ for(item = curr; item != next; item = item->right) { ++ dc->y += dc->h; ++ if(ev->y >= dc->y && ev->y <= (dc->y + dc->h)) { ++ puts(item->text); ++ exit(EXIT_SUCCESS); ++ } ++ } ++ } ++ else if(matches) { ++ /* left-click on left arrow */ ++ dc->x += inputw; ++ dc->w = textw(dc, "<"); ++ if(prev && curr->left) { ++ if(ev->x >= dc->x && ev->x <= dc->x + dc->w) { ++ sel = curr = prev; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ } ++ /* horizontal list: left-click on item */ ++ for(item = curr; item != next; item = item->right) { ++ dc->x += dc->w; ++ dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">")); ++ if(ev->x >= dc->x && ev->x <= (dc->x + dc->w)) { ++ puts(item->text); ++ exit(EXIT_SUCCESS); ++ } ++ } ++ /* left-click on right arrow */ ++ dc->w = textw(dc, ">"); ++ dc->x = mw - dc->w; ++ if(next && ev->x >= dc->x && ev->x <= dc->x + dc->w) { ++ sel = curr = next; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ } ++} ++ ++void + match(void) { + static char **tokv = NULL; + static int tokn = 0; +@@ -496,6 +601,9 @@ run(void) { + if(XFilterEvent(&ev, win)) + continue; + switch(ev.type) { ++ case ButtonPress: ++ buttonpress(&ev); ++ break; + case Expose: + if(ev.xexpose.count == 0) + mapdc(dc, win, mw, mh); +@@ -585,8 +693,9 @@ setup(void) { + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = normcol->BG; +- swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; ++ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | ++ ButtonPressMask; + win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, + DefaultDepth(dc->dpy, screen), CopyFromParent, + DefaultVisual(dc->dpy, screen), + CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); diff --git a/dmenu-4.5-xft.diff b/dmenu-4.5-xft.diff new file mode 100644 index 000000000000..ff93337ca276 --- /dev/null +++ b/dmenu-4.5-xft.diff @@ -0,0 +1,418 @@ +diff -upr a/config.mk b/config.mk +--- a/config.mk 2012-01-10 19:03:22.000000000 +0200 ++++ b/config.mk 2012-01-10 19:03:38.000000000 +0200 +@@ -12,9 +12,13 @@ X11LIB = /usr/X11R6/lib + XINERAMALIBS = -lXinerama + XINERAMAFLAGS = -DXINERAMA + ++# Xft, comment if you don't want it ++XFTINC = -I/usr/include/freetype2 ++XFTLIBS = -lXft -lXrender -lfreetype -lz -lfontconfig ++ + # includes and libs +-INCS = -I${X11INC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ++INCS = -I${X11INC} ${XFTINC} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${XFTLIBS} + + # flags + CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff -upr a/dmenu.1 b/dmenu.1 +--- a/dmenu.1 2012-01-10 19:14:19.000000000 +0200 ++++ b/dmenu.1 2012-01-10 19:14:23.000000000 +0200 +@@ -53,7 +53,7 @@ dmenu lists items vertically, with the g + defines the prompt to be displayed to the left of the input field. + .TP + .BI \-fn " font" +-defines the font or font set used. ++defines the font or font set used. eg. "fixed" or "Monospace-12:normal" (an xft font) + .TP + .BI \-nb " color" + defines the normal background color. +diff -upr a/dmenu.c b/dmenu.c +--- a/dmenu.c 2012-01-10 19:14:19.000000000 +0200 ++++ b/dmenu.c 2012-01-10 19:24:39.000000000 +0200 +@@ -17,6 +17,7 @@ + * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) + #define MIN(a,b) ((a) < (b) ? (a) : (b)) + #define MAX(a,b) ((a) > (b) ? (a) : (b)) ++#define DEFFONT "fixed" /* xft example: "Monospace-11" */ + + typedef struct Item Item; + struct Item { +@@ -26,6 +27,7 @@ struct Item { + + static void appenditem(Item *item, Item **list, Item **last); + static void calcoffsets(void); ++static void cleanup(void); + static char *cistrstr(const char *s, const char *sub); + static void drawmenu(void); + static void grabkeyboard(void); +@@ -50,10 +52,12 @@ static const char *normfgcolor = "#bbbbb + static const char *selbgcolor = "#005577"; + static const char *selfgcolor = "#eeeeee"; + static unsigned int lines = 0; +-static unsigned long normcol[ColLast]; +-static unsigned long selcol[ColLast]; ++static ColorSet *normcol; ++static ColorSet *selcol; + static Atom clip, utf8; + static Bool topbar = True; ++static Bool running = True; ++static int ret = 0; + static DC *dc; + static Item *items = NULL; + static Item *matches, *matchend; +@@ -104,7 +108,9 @@ main(int argc, char *argv[]) { + usage(); + + dc = initdc(); +- initfont(dc, font); ++ initfont(dc, font ? font : DEFFONT); ++ normcol = initcolor(dc, normfgcolor, normbgcolor); ++ selcol = initcolor(dc, selfgcolor, selbgcolor); + + if(fast) { + grabkeyboard(); +@@ -117,7 +123,8 @@ main(int argc, char *argv[]) { + setup(); + run(); + +- return 1; /* unreachable */ ++ cleanup(); ++ return ret; + } + + void +@@ -160,6 +167,15 @@ cistrstr(const char *s, const char *sub) + } + + void ++cleanup(void) { ++ freecol(dc, normcol); ++ freecol(dc, selcol); ++ XDestroyWindow(dc->dpy, win); ++ XUngrabKeyboard(dc->dpy, CurrentTime); ++ freedc(dc); ++} ++ ++void + drawmenu(void) { + int curpos; + Item *item; +@@ -167,7 +183,7 @@ drawmenu(void) { + dc->x = 0; + dc->y = 0; + dc->h = bh; +- drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol)); ++ drawrect(dc, 0, 0, mw, mh, True, normcol->BG); + + if(prompt) { + dc->w = promptw; +@@ -178,7 +194,7 @@ drawmenu(void) { + dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; + drawtext(dc, text, normcol); + if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w) +- drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol)); ++ drawrect(dc, curpos, 2, 1, dc->h - 4, True, normcol->FG); + + if(lines > 0) { + /* draw vertical list */ +@@ -321,7 +337,8 @@ keypress(XKeyEvent *ev) { + sel = matchend; + break; + case XK_Escape: +- exit(EXIT_FAILURE); ++ ret = EXIT_FAILURE; ++ running = False; + case XK_Home: + if(sel == matches) { + cursor = 0; +@@ -359,7 +376,8 @@ keypress(XKeyEvent *ev) { + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); +- exit(EXIT_SUCCESS); ++ ret = EXIT_SUCCESS; ++ running = False; + case XK_Right: + if(text[cursor] != '\0') { + cursor = nextrune(+1); +@@ -490,7 +508,7 @@ void + run(void) { + XEvent ev; + +- while(!XNextEvent(dc->dpy, &ev)) { ++ while(running && !XNextEvent(dc->dpy, &ev)) { + if(XFilterEvent(&ev, win)) + continue; + switch(ev.type) { +@@ -524,11 +542,6 @@ setup(void) { + XineramaScreenInfo *info; + #endif + +- normcol[ColBG] = getcolor(dc, normbgcolor); +- normcol[ColFG] = getcolor(dc, normfgcolor); +- selcol[ColBG] = getcolor(dc, selbgcolor); +- selcol[ColFG] = getcolor(dc, selfgcolor); +- + clip = XInternAtom(dc->dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); + +@@ -582,7 +595,7 @@ setup(void) { + + /* create menu window */ + swa.override_redirect = True; +- swa.background_pixel = normcol[ColBG]; ++ swa.background_pixel = normcol->BG; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, + DefaultDepth(dc->dpy, screen), CopyFromParent, +diff -upr a/draw.c b/draw.c +--- a/draw.c 2012-01-10 19:14:19.000000000 +0200 ++++ b/draw.c 2012-01-10 19:14:23.000000000 +0200 +@@ -9,9 +9,6 @@ + + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + #define MIN(a, b) ((a) < (b) ? (a) : (b)) +-#define DEFAULTFN "fixed" +- +-static Bool loadfont(DC *dc, const char *fontstr); + + void + drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color) { +@@ -23,7 +20,7 @@ drawrect(DC *dc, int x, int y, unsigned + } + + void +-drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { ++drawtext(DC *dc, const char *text, ColorSet *col) { + char buf[BUFSIZ]; + size_t mn, n = strlen(text); + +@@ -35,19 +32,24 @@ drawtext(DC *dc, const char *text, unsig + if(mn < n) + for(n = MAX(mn-3, 0); n < mn; buf[n++] = '.'); + +- drawrect(dc, 0, 0, dc->w, dc->h, True, BG(dc, col)); ++ drawrect(dc, 0, 0, dc->w, dc->h, True, col->BG); + drawtextn(dc, buf, mn, col); + } + + void +-drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) { ++drawtextn(DC *dc, const char *text, size_t n, ColorSet *col) { + int x = dc->x + dc->font.height/2; + int y = dc->y + dc->font.ascent+1; + +- XSetForeground(dc->dpy, dc->gc, FG(dc, col)); +- if(dc->font.set) ++ XSetForeground(dc->dpy, dc->gc, col->FG); ++ if(dc->font.xft_font) { ++ if (!dc->xftdraw) ++ eprintf("error, xft drawable does not exist"); ++ XftDrawStringUtf8(dc->xftdraw, &col->FG_xft, ++ dc->font.xft_font, x, y, (unsigned char*)text, n); ++ } else if(dc->font.set) { + XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, text, n); +- else { ++ } else { + XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid); + XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n); + } +@@ -69,16 +71,33 @@ eprintf(const char *fmt, ...) { + } + + void ++freecol(DC *dc, ColorSet *col) { ++ if(col) { ++ if(&col->FG_xft) ++ XftColorFree(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), ++ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), &col->FG_xft); ++ free(col); ++ } ++} ++ ++void + freedc(DC *dc) { ++ if(dc->font.xft_font) { ++ XftFontClose(dc->dpy, dc->font.xft_font); ++ XftDrawDestroy(dc->xftdraw); ++ } + if(dc->font.set) + XFreeFontSet(dc->dpy, dc->font.set); +- if(dc->font.xfont) ++ if(dc->font.xfont) + XFreeFont(dc->dpy, dc->font.xfont); +- if(dc->canvas) ++ if(dc->canvas) + XFreePixmap(dc->dpy, dc->canvas); +- XFreeGC(dc->dpy, dc->gc); +- XCloseDisplay(dc->dpy); +- free(dc); ++ if(dc->gc) ++ XFreeGC(dc->dpy, dc->gc); ++ if(dc->dpy) ++ XCloseDisplay(dc->dpy); ++ if(dc) ++ free(dc); + } + + unsigned long +@@ -91,6 +110,20 @@ getcolor(DC *dc, const char *colstr) { + return color.pixel; + } + ++ColorSet * ++initcolor(DC *dc, const char * foreground, const char * background) { ++ ColorSet * col = (ColorSet *)malloc(sizeof(ColorSet)); ++ if(!col) ++ eprintf("error, cannot allocate memory for color set"); ++ col->BG = getcolor(dc, background); ++ col->FG = getcolor(dc, foreground); ++ if(dc->font.xft_font) ++ if(!XftColorAllocName(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), ++ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), foreground, &col->FG_xft)) ++ eprintf("error, cannot allocate xft font color '%s'\n", foreground); ++ return col; ++} ++ + DC * + initdc(void) { + DC *dc; +@@ -109,39 +142,33 @@ initdc(void) { + + void + initfont(DC *dc, const char *fontstr) { +- if(!loadfont(dc, fontstr ? fontstr : DEFAULTFN)) { +- if(fontstr != NULL) +- fprintf(stderr, "cannot load font '%s'\n", fontstr); +- if(fontstr == NULL || !loadfont(dc, DEFAULTFN)) +- eprintf("cannot load font '%s'\n", DEFAULTFN); +- } +- dc->font.height = dc->font.ascent + dc->font.descent; +-} +- +-Bool +-loadfont(DC *dc, const char *fontstr) { + char *def, **missing, **names; + int i, n; + XFontStruct **xfonts; + +- if(!*fontstr) +- return False; +- if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { ++ missing = NULL; ++ if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { ++ dc->font.ascent = dc->font.xfont->ascent; ++ dc->font.descent = dc->font.xfont->descent; ++ dc->font.width = dc->font.xfont->max_bounds.width; ++ } else if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { + n = XFontsOfFontSet(dc->font.set, &xfonts, &names); + for(i = 0; i < n; i++) { + dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); + dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); + dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); + } +- } +- else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { +- dc->font.ascent = dc->font.xfont->ascent; +- dc->font.descent = dc->font.xfont->descent; +- dc->font.width = dc->font.xfont->max_bounds.width; ++ } else if((dc->font.xft_font = XftFontOpenName(dc->dpy, DefaultScreen(dc->dpy), fontstr))) { ++ dc->font.ascent = dc->font.xft_font->ascent; ++ dc->font.descent = dc->font.xft_font->descent; ++ dc->font.width = dc->font.xft_font->max_advance_width; ++ } else { ++ eprintf("cannot load font '%s'\n", fontstr); + } + if(missing) + XFreeStringList(missing); +- return dc->font.set || dc->font.xfont; ++ dc->font.height = dc->font.ascent + dc->font.descent; ++ return; + } + + void +@@ -151,20 +178,29 @@ mapdc(DC *dc, Window win, unsigned int w + + void + resizedc(DC *dc, unsigned int w, unsigned int h) { ++ int screen = DefaultScreen(dc->dpy); + if(dc->canvas) + XFreePixmap(dc->dpy, dc->canvas); + + dc->w = w; + dc->h = h; + dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, +- DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); ++ DefaultDepth(dc->dpy, screen)); ++ if(dc->font.xft_font && !(dc->xftdraw)) { ++ dc->xftdraw = XftDrawCreate(dc->dpy, dc->canvas, DefaultVisual(dc->dpy,screen), DefaultColormap(dc->dpy,screen)); ++ if(!(dc->xftdraw)) ++ eprintf("error, cannot create xft drawable\n"); ++ } + } + + int + textnw(DC *dc, const char *text, size_t len) { +- if(dc->font.set) { ++ if(dc->font.xft_font) { ++ XGlyphInfo gi; ++ XftTextExtentsUtf8(dc->dpy, dc->font.xft_font, (const FcChar8*)text, len, &gi); ++ return gi.width; ++ } else if(dc->font.set) { + XRectangle r; +- + XmbTextExtents(dc->font.set, text, len, NULL, &r); + return r.width; + } +diff -upr a/draw.h b/draw.h +--- a/draw.h 2012-01-10 19:14:19.000000000 +0200 ++++ b/draw.h 2012-01-10 19:14:23.000000000 +0200 +@@ -1,9 +1,6 @@ + /* See LICENSE file for copyright and license details. */ + +-#define FG(dc, col) ((col)[(dc)->invert ? ColBG : ColFG]) +-#define BG(dc, col) ((col)[(dc)->invert ? ColFG : ColBG]) +- +-enum { ColBG, ColFG, ColBorder, ColLast }; ++#include <X11/Xft/Xft.h> + + typedef struct { + int x, y, w, h; +@@ -11,6 +8,7 @@ typedef struct { + Display *dpy; + GC gc; + Pixmap canvas; ++ XftDraw *xftdraw; + struct { + int ascent; + int descent; +@@ -18,15 +16,24 @@ typedef struct { + int width; + XFontSet set; + XFontStruct *xfont; ++ XftFont *xft_font; + } font; + } DC; /* draw context */ + ++typedef struct { ++ unsigned long FG; ++ XftColor FG_xft; ++ unsigned long BG; ++} ColorSet; ++ + void drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color); +-void drawtext(DC *dc, const char *text, unsigned long col[ColLast]); +-void drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]); ++void drawtext(DC *dc, const char *text, ColorSet *col); ++void drawtextn(DC *dc, const char *text, size_t n, ColorSet *col); ++void freecol(DC *dc, ColorSet *col); + void eprintf(const char *fmt, ...); + void freedc(DC *dc); + unsigned long getcolor(DC *dc, const char *colstr); ++ColorSet *initcolor(DC *dc, const char *foreground, const char *background); + DC *initdc(void); + void initfont(DC *dc, const char *fontstr); + void mapdc(DC *dc, Window win, unsigned int w, unsigned int h); |