From 569a1f925a7cf351e6ec3e38529f46a1d9becf3f Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sat, 28 Nov 2009 12:28:15 +0000 Subject: [PATCH 01/16] applied cursor, vertical and paste patches for upcoming 4.1 dmenu version (due to the fact that surf is using dmenu as well) --- LICENSE | 5 +- config.mk | 2 +- dmenu.1 | 7 ++- dmenu.c | 163 +++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 149 insertions(+), 28 deletions(-) diff --git a/LICENSE b/LICENSE index 8f13918..1f2db9b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,9 @@ MIT/X Consortium License -© 2006-2008 Anselm R. Garbe +© 2006-2009 Anselm R. Garbe +© 2009 Gottox +© 2009 Markus Schnalke +© 2009 Evan Gates © 2006-2008 Sander van Dijk © 2006-2007 Michał Janeczek diff --git a/config.mk b/config.mk index f6a3652..75c6abe 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # dmenu version -VERSION = 4.0 +VERSION = 4.1 # Customize below to fit your system diff --git a/dmenu.1 b/dmenu.1 index a072883..24ee38b 100644 --- a/dmenu.1 +++ b/dmenu.1 @@ -5,6 +5,7 @@ dmenu \- dynamic menu .B dmenu .RB [ \-i ] .RB [ \-b ] +.RB [ \-l " "] .RB [ \-fn " "] .RB [ \-nb " "] .RB [ \-nf " "] @@ -26,6 +27,10 @@ makes dmenu match menu entries case insensitively. .B \-b defines that dmenu appears at the bottom. .TP +.B \-l +activates vertical list mode. +The given number of lines will be displayed. Window height will get adjusted. +.TP .B \-fn defines the font. .TP @@ -57,7 +62,7 @@ dmenu is completely controlled by the keyboard. The following keys are recognize Appends the character to the text in the input field. This works as a filter: only items containing this text will be displayed. .TP -.B Left/Right (Mod1\-h/Mod1\-l) +.B Left/Right (Up/Down) (Mod1\-h/Mod1\-l) Select the previous/next item. .TP .B PageUp/PageDown (Mod1\-k/Mod1\-j) diff --git a/dmenu.c b/dmenu.c index 0f95af6..be9b41b 100644 --- a/dmenu.c +++ b/dmenu.c @@ -18,6 +18,7 @@ #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) /* enums */ enum { ColFG, ColBG, ColLast }; @@ -47,10 +48,12 @@ struct Item { /* forward declarations */ static void appenditem(Item *i, Item **list, Item **last); -static void calcoffsets(void); +static void calcoffsetsh(void); +static void calcoffsetsv(void); static char *cistrstr(const char *s, const char *sub); static void cleanup(void); -static void drawmenu(void); +static void drawmenuh(void); +static void drawmenuv(void); static void drawtext(const char *text, unsigned long col[ColLast]); static void eprint(const char *errstr, ...); static unsigned long getcolor(const char *colstr); @@ -73,6 +76,7 @@ static char text[4096]; static int cmdw = 0; static int promptw = 0; static int ret = 0; +static int cursor = 0; static int screen; static unsigned int mw, mh; static unsigned int numlockmask = 0; @@ -88,6 +92,10 @@ static Item *curr = NULL; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t n) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; +static Bool vlist = False; +static unsigned int lines = 5; +static void (*calcoffsets)(void) = calcoffsetsh; +static void (*drawmenu)(void) = drawmenuh; void appenditem(Item *i, Item **list, Item **last) { @@ -101,7 +109,7 @@ appenditem(Item *i, Item **list, Item **last) { } void -calcoffsets(void) { +calcoffsetsh(void) { int tw; unsigned int w; @@ -127,6 +135,26 @@ calcoffsets(void) { } } +void +calcoffsetsv(void) { + static unsigned int w; + + if(!curr) + return; + w = (dc.font.height + 2) * (lines + 1); + for(next = curr; next; next=next->right) { + w -= dc.font.height + 2; + if(w <= 0) + break; + } + w = (dc.font.height + 2) * (lines + 1); + for(prev = curr; prev && prev->left; prev=prev->left) { + w -= dc.font.height + 2; + if(w <= 0) + break; + } +} + char * cistrstr(const char *s, const char *sub) { int c, csub; @@ -171,7 +199,17 @@ cleanup(void) { } void -drawmenu(void) { +drawcursor(void) { + XRectangle r = { dc.x, dc.y + 2, 1, dc.h - 4 }; + + r.x += textnw(text, cursor) + dc.font.height / 2; + + XSetForeground(dpy, dc.gc, dc.norm[ColFG]); + XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); +} + +void +drawmenuh(void) { Item *i; dc.x = 0; @@ -190,6 +228,7 @@ drawmenu(void) { if(cmdw && item) dc.w = cmdw; drawtext(text[0] ? text : NULL, dc.norm); + drawcursor(); dc.x += cmdw; if(curr) { dc.w = spaceitem; @@ -211,6 +250,39 @@ drawmenu(void) { XFlush(dpy); } +void +drawmenuv(void) { + Item *i; + + dc.x = 0; + dc.y = 0; + dc.w = mw; + dc.h = mh; + drawtext(NULL, dc.norm); + /* print prompt? */ + if(promptw) { + dc.w = promptw; + drawtext(prompt, dc.sel); + } + dc.x += promptw; + dc.w = mw - promptw; + /* print command */ + drawtext(text[0] ? text : NULL, dc.norm); + if(curr) { + dc.x = 0; + dc.w = mw; + dc.y += dc.font.height + 2; + /* determine maximum items */ + for(i = curr; i != next; i=i->right) { + drawtext(i->text, (sel == i) ? dc.sel : dc.norm); + dc.y += dc.font.height + 2; + } + drawtext(NULL, dc.norm); + } + XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0); + XFlush(dpy); +} + void drawtext(const char *text, unsigned long col[ColLast]) { char buf[256]; @@ -222,8 +294,8 @@ drawtext(const char *text, unsigned long col[ColLast]) { if(!text) return; olen = strlen(text); - h = dc.font.ascent + dc.font.descent; - y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; + h = dc.font.height; + y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent; x = dc.x + (h / 2); /* shorten text if necessary */ for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--); @@ -353,7 +425,7 @@ kpress(XKeyEvent * e) { text[0] = 0; match(text); drawmenu(); - return; + break; case XK_w: case XK_W: if(len) { @@ -365,7 +437,7 @@ kpress(XKeyEvent * e) { match(text); drawmenu(); } - return; + break; } } if(CLEANMASK(e->state) & Mod1Mask) { @@ -389,19 +461,39 @@ kpress(XKeyEvent * e) { case XK_G: ksym = XK_End; break; + case XK_p: + { + FILE *fp; + char *c; + if(!(fp = (FILE*)popen("sselp", "r"))) + fprintf(stderr, "dmenu: Could not popen sselp\n"); + c = fgets(text + len, sizeof(text) - len, fp); + pclose(fp); + if(c == NULL) + return; + } + len = strlen(text); + if(len && text[len-1] == '\n') + text[--len] = '\0'; + match(text); + drawmenu(); + return; } } switch(ksym) { default: if(num && !iscntrl((int) buf[0])) { buf[num] = 0; - strncpy(text + len, buf, sizeof text - len); + memmove(text + cursor + num, text + cursor, sizeof text - cursor); + strncpy(text + cursor, buf, sizeof text - cursor); + cursor+=num; match(text); } break; case XK_BackSpace: - if(len) { - text[--len] = 0; + if(cursor > 0) { + memmove(text + cursor + -1, text + cursor, sizeof text - cursor); + cursor--; match(text); } break; @@ -426,13 +518,18 @@ kpress(XKeyEvent * e) { calcoffsets(); break; case XK_Left: - if(!(sel && sel->left)) - return; - sel=sel->left; - if(sel->right == curr) { - curr = prev; - calcoffsets(); + case XK_Up: + if(sel && sel->left){ + sel=sel->left; + if(sel->right == curr) { + curr = prev; + calcoffsets(); + } } + else if(cursor > 0) + cursor--; + else + return; break; case XK_Next: if(!next) @@ -457,21 +554,30 @@ kpress(XKeyEvent * e) { running = False; break; case XK_Right: - if(!(sel && sel->right)) - return; - sel=sel->right; - if(sel == next) { - curr = next; - calcoffsets(); + case XK_Down: + if(cursor < len) + cursor++; + else if(sel && sel->right) { + sel=sel->right; + if(sel == next) { + curr = next; + calcoffsets(); + } } + else + return; break; case XK_Tab: if(!sel) return; strncpy(text, sel->text, sizeof text); + cursor = strlen(text); match(text); break; } + len = strlen(text); + cursor = MIN(cursor, len); + cursor = MAX(cursor, 0); drawmenu(); } @@ -598,6 +704,7 @@ setup(Bool topbar) { /* menu window geometry */ mh = dc.font.height + 2; + mh = vlist ? mh * (lines+1) : mh; #if XINERAMA if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { i = 0; @@ -676,6 +783,12 @@ main(int argc, char *argv[]) { } else if(!strcmp(argv[i], "-b")) topbar = False; + else if(!strcmp(argv[i], "-l")) { + vlist = True; + calcoffsets = calcoffsetsv; + drawmenu = drawmenuv; + if(++i < argc) lines += atoi(argv[i]); + } else if(!strcmp(argv[i], "-fn")) { if(++i < argc) font = argv[i]; } @@ -695,9 +808,9 @@ main(int argc, char *argv[]) { if(++i < argc) selfgcolor = argv[i]; } else if(!strcmp(argv[i], "-v")) - eprint("dmenu-"VERSION", © 2006-2008 dmenu engineers, see LICENSE for details\n"); + eprint("dmenu-"VERSION", © 2006-2009 dmenu engineers, see LICENSE for details\n"); else - eprint("usage: dmenu [-i] [-b] [-fn ] [-nb ] [-nf ]\n" + eprint("usage: dmenu [-i] [-b] [-l ] [-fn ] [-nb ] [-nf ]\n" " [-p ] [-sb ] [-sf ] [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); -- 2.20.1 From 7082ba1e1050664309de707bbc5b7194a53ed5ac Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sat, 5 Dec 2009 16:52:53 +0000 Subject: [PATCH 02/16] this is only a temporary workaround, the command executed by -p must be configurable through some switch, that was the initial idea, just using sselp is too limited, I'll look into the other issues soon --- dmenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index be9b41b..1f7abca 100644 --- a/dmenu.c +++ b/dmenu.c @@ -466,7 +466,7 @@ kpress(XKeyEvent * e) { FILE *fp; char *c; if(!(fp = (FILE*)popen("sselp", "r"))) - fprintf(stderr, "dmenu: Could not popen sselp\n"); + eprint("dmenu: Could not popen sselp\n"); c = fgets(text + len, sizeof(text) - len, fp); pclose(fp); if(c == NULL) -- 2.20.1 From 37236f8840624d5e9d590e7be9ba365bc61913a6 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sun, 7 Mar 2010 08:32:16 +0000 Subject: [PATCH 03/16] applied Connor's patch, thanks! --- dmenu.c | 77 +++++++++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/dmenu.c b/dmenu.c index 1f7abca..aef8ae5 100644 --- a/dmenu.c +++ b/dmenu.c @@ -52,6 +52,7 @@ static void calcoffsetsh(void); static void calcoffsetsv(void); static char *cistrstr(const char *s, const char *sub); static void cleanup(void); +static void drawmenu(void); static void drawmenuh(void); static void drawmenuv(void); static void drawtext(const char *text, unsigned long col[ColLast]); @@ -95,7 +96,6 @@ static char *(*fstrstr)(const char *, const char *) = strstr; static Bool vlist = False; static unsigned int lines = 5; static void (*calcoffsets)(void) = calcoffsetsh; -static void (*drawmenu)(void) = drawmenuh; void appenditem(Item *i, Item **list, Item **last) { @@ -200,7 +200,7 @@ cleanup(void) { void drawcursor(void) { - XRectangle r = { dc.x, dc.y + 2, 1, dc.h - 4 }; + XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 }; r.x += textnw(text, cursor) + dc.font.height / 2; @@ -209,9 +209,7 @@ drawcursor(void) { } void -drawmenuh(void) { - Item *i; - +drawmenu(void) { dc.x = 0; dc.y = 0; dc.w = mw; @@ -231,56 +229,48 @@ drawmenuh(void) { drawcursor(); dc.x += cmdw; if(curr) { - dc.w = spaceitem; - drawtext((curr && curr->left) ? "<" : NULL, dc.norm); - dc.x += dc.w; - /* determine maximum items */ - for(i = curr; i != next; i=i->right) { - dc.w = textw(i->text); - if(dc.w > mw / 3) - dc.w = mw / 3; - drawtext(i->text, (sel == i) ? dc.sel : dc.norm); - dc.x += dc.w; - } - dc.x = mw - spaceitem; - dc.w = spaceitem; - drawtext(next ? ">" : NULL, dc.norm); + if(vlist) + drawmenuv(); + else + drawmenuh(); } XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0); XFlush(dpy); } +void +drawmenuh(void) { + Item *i; + + dc.w = spaceitem; + drawtext((curr && curr->left) ? "<" : NULL, dc.norm); + dc.x += dc.w; + /* determine maximum items */ + for(i = curr; i != next; i=i->right) { + dc.w = textw(i->text); + if(dc.w > mw / 3) + dc.w = mw / 3; + drawtext(i->text, (sel == i) ? dc.sel : dc.norm); + dc.x += dc.w; + } + dc.x = mw - spaceitem; + dc.w = spaceitem; + drawtext(next ? ">" : NULL, dc.norm); +} + void drawmenuv(void) { Item *i; dc.x = 0; - dc.y = 0; dc.w = mw; - dc.h = mh; - drawtext(NULL, dc.norm); - /* print prompt? */ - if(promptw) { - dc.w = promptw; - drawtext(prompt, dc.sel); - } - dc.x += promptw; - dc.w = mw - promptw; - /* print command */ - drawtext(text[0] ? text : NULL, dc.norm); - if(curr) { - dc.x = 0; - dc.w = mw; + dc.y += dc.font.height + 2; + /* determine maximum items */ + for(i = curr; i != next; i=i->right) { + drawtext(i->text, (sel == i) ? dc.sel : dc.norm); dc.y += dc.font.height + 2; - /* determine maximum items */ - for(i = curr; i != next; i=i->right) { - drawtext(i->text, (sel == i) ? dc.sel : dc.norm); - dc.y += dc.font.height + 2; - } - drawtext(NULL, dc.norm); } - XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0); - XFlush(dpy); + drawtext(NULL, dc.norm); } void @@ -786,8 +776,7 @@ main(int argc, char *argv[]) { else if(!strcmp(argv[i], "-l")) { vlist = True; calcoffsets = calcoffsetsv; - drawmenu = drawmenuv; - if(++i < argc) lines += atoi(argv[i]); + if(++i < argc) lines = atoi(argv[i]); } else if(!strcmp(argv[i], "-fn")) { if(++i < argc) font = argv[i]; -- 2.20.1 From 8e3e61170bd34d8a8269e376c30cb3afa25343a2 Mon Sep 17 00:00:00 2001 From: "anselm@garbe.us" Date: Mon, 22 Mar 2010 07:50:26 +0000 Subject: [PATCH 04/16] applied cls' patch, thanks Connor! --- dmenu.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/dmenu.c b/dmenu.c index aef8ae5..5f16894 100644 --- a/dmenu.c +++ b/dmenu.c @@ -372,7 +372,7 @@ initfont(const char *fontstr) { void kpress(XKeyEvent * e) { - char buf[32]; + char buf[sizeof text]; int i, num; unsigned int len; KeySym ksym; @@ -457,25 +457,23 @@ kpress(XKeyEvent * e) { char *c; if(!(fp = (FILE*)popen("sselp", "r"))) eprint("dmenu: Could not popen sselp\n"); - c = fgets(text + len, sizeof(text) - len, fp); + c = fgets(buf, sizeof buf, fp); pclose(fp); if(c == NULL) return; } - len = strlen(text); - if(len && text[len-1] == '\n') - text[--len] = '\0'; - match(text); - drawmenu(); - return; + num = strlen(buf); + if(num && buf[num-1] == '\n') + buf[--num] = '\0'; + break; } } switch(ksym) { default: + num = MIN(num, sizeof text - cursor); if(num && !iscntrl((int) buf[0])) { - buf[num] = 0; - memmove(text + cursor + num, text + cursor, sizeof text - cursor); - strncpy(text + cursor, buf, sizeof text - cursor); + memmove(text + cursor + num, text + cursor, sizeof text - cursor - num); + memmove(text + cursor, buf, num); cursor+=num; match(text); } @@ -487,6 +485,10 @@ kpress(XKeyEvent * e) { match(text); } break; + case XK_Delete: + memmove(text + cursor, text + cursor + 1, sizeof text - cursor); + match(text); + break; case XK_End: if(!item) return; -- 2.20.1 From eededaa76fb12c10d6de3cb5fcf1479efd39ad75 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 31 Mar 2010 22:37:41 +0100 Subject: [PATCH 05/16] applied Connor's next nice patch, thanks a lot! --- dmenu.c | 65 +++++++++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/dmenu.c b/dmenu.c index 5f16894..6177906 100644 --- a/dmenu.c +++ b/dmenu.c @@ -52,6 +52,7 @@ static void calcoffsetsh(void); static void calcoffsetsv(void); static char *cistrstr(const char *s, const char *sub); static void cleanup(void); +static void drawcursor(void); static void drawmenu(void); static void drawmenuh(void); static void drawmenuv(void); @@ -247,9 +248,7 @@ drawmenuh(void) { dc.x += dc.w; /* determine maximum items */ for(i = curr; i != next; i=i->right) { - dc.w = textw(i->text); - if(dc.w > mw / 3) - dc.w = mw / 3; + dc.w = MIN(textw(i->text), mw / 3); drawtext(i->text, (sel == i) ? dc.sel : dc.norm); dc.x += dc.w; } @@ -395,7 +394,8 @@ kpress(XKeyEvent * e) { switch (ksym) { default: /* ignore other control sequences */ return; - case XK_bracketleft: + case XK_c: + case XK_C: ksym = XK_Escape; break; case XK_h: @@ -414,18 +414,16 @@ kpress(XKeyEvent * e) { case XK_U: text[0] = 0; match(text); - drawmenu(); break; case XK_w: case XK_W: - if(len) { - i = len - 1; - while(i >= 0 && text[i] == ' ') - text[i--] = 0; - while(i >= 0 && text[i] != ' ') - text[i--] = 0; + if(cursor > 0) { + i = cursor; + while(i-- > 0 && text[i] == ' '); + while(i-- > 0 && text[i] != ' '); + memmove(text + i + 1, text + cursor, sizeof text - cursor); + cursor = i + 1; match(text); - drawmenu(); } break; } @@ -473,14 +471,14 @@ kpress(XKeyEvent * e) { num = MIN(num, sizeof text - cursor); if(num && !iscntrl((int) buf[0])) { memmove(text + cursor + num, text + cursor, sizeof text - cursor - num); - memmove(text + cursor, buf, num); + memcpy(text + cursor, buf, num); cursor+=num; match(text); } break; case XK_BackSpace: if(cursor > 0) { - memmove(text + cursor + -1, text + cursor, sizeof text - cursor); + memmove(text + cursor - 1, text + cursor, sizeof text - cursor + 1); cursor--; match(text); } @@ -490,8 +488,10 @@ kpress(XKeyEvent * e) { match(text); break; case XK_End: - if(!item) - return; + if(cursor < len) { + cursor = len; + break; + } while(next) { sel = curr = next; calcoffsets(); @@ -504,8 +504,10 @@ kpress(XKeyEvent * e) { running = False; break; case XK_Home: - if(!item) - return; + if(sel == item) { + cursor = 0; + break; + } sel = curr = item; calcoffsets(); break; @@ -536,12 +538,10 @@ kpress(XKeyEvent * e) { calcoffsets(); break; case XK_Return: - if((e->state & ShiftMask) && *text) + if((e->state & ShiftMask) || !sel) fprintf(stdout, "%s", text); - else if(sel) + else fprintf(stdout, "%s", sel->text); - else if(*text) - fprintf(stdout, "%s", text); fflush(stdout); running = False; break; @@ -567,9 +567,6 @@ kpress(XKeyEvent * e) { match(text); break; } - len = strlen(text); - cursor = MIN(cursor, len); - cursor = MAX(cursor, 0); drawmenu(); } @@ -620,13 +617,13 @@ readstdin(void) { unsigned int len = 0, max = 0; Item *i, *new; - i = 0; + i = NULL; while(fgets(buf, sizeof buf, stdin)) { len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = 0; + if(buf[len-1] == '\n') + buf[--len] = '\0'; if(!(p = strdup(buf))) - eprint("fatal: could not strdup() %u bytes\n", strlen(buf)); + eprint("fatal: could not strdup() %u bytes\n", len); if(max < len) { maxname = p; max = len; @@ -734,13 +731,9 @@ setup(Bool topbar) { if(!dc.font.set) XSetFont(dpy, dc.gc, dc.font.xfont->fid); if(maxname) - cmdw = textw(maxname); - if(cmdw > mw / 3) - cmdw = mw / 3; + cmdw = MIN(textw(maxname), mw / 3); if(prompt) - promptw = textw(prompt); - if(promptw > mw / 5) - promptw = mw / 5; + promptw = MIN(textw(prompt), mw / 5); text[0] = 0; match(text); XMapRaised(dpy, win); @@ -799,7 +792,7 @@ main(int argc, char *argv[]) { if(++i < argc) selfgcolor = argv[i]; } else if(!strcmp(argv[i], "-v")) - eprint("dmenu-"VERSION", © 2006-2009 dmenu engineers, see LICENSE for details\n"); + eprint("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n"); else eprint("usage: dmenu [-i] [-b] [-l ] [-fn ] [-nb ] [-nf ]\n" " [-p ] [-sb ] [-sf ] [-v]\n"); -- 2.20.1 From 052ffae1924a2760baa32f41e01de82e73e0bc5e Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 31 Mar 2010 22:43:49 +0100 Subject: [PATCH 06/16] applied Connor's subwindow patch --- dmenu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index 6177906..fd9baaa 100644 --- a/dmenu.c +++ b/dmenu.c @@ -768,6 +768,9 @@ main(int argc, char *argv[]) { } else if(!strcmp(argv[i], "-b")) topbar = False; + else if(!strcmp(argv[i], "-e")) { + if(++i < argc) root = atoi(argv[i]); + } else if(!strcmp(argv[i], "-l")) { vlist = True; calcoffsets = calcoffsetsv; @@ -801,7 +804,8 @@ main(int argc, char *argv[]) { if(!(dpy = XOpenDisplay(NULL))) eprint("dmenu: cannot open display\n"); screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); + if(!root) + root = RootWindow(dpy, screen); if(isatty(STDIN_FILENO)) { readstdin(); -- 2.20.1 From 29686bd1b8513ba7512ab089cfdbc7df44986409 Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 1 Apr 2010 19:10:41 +0200 Subject: [PATCH 07/16] add ^a and ^e keybindings --- dmenu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dmenu.c b/dmenu.c index fd9baaa..4c87d6a 100644 --- a/dmenu.c +++ b/dmenu.c @@ -394,6 +394,14 @@ kpress(XKeyEvent * e) { switch (ksym) { default: /* ignore other control sequences */ return; + case XK_a: + case XK_A: + cursor = 0; + break; + case XK_e: + case XK_E: + cursor = strlen(text); + break; case XK_c: case XK_C: ksym = XK_Escape; -- 2.20.1 From 7ffe51981607c72abc969b23e79a1a46f6e2e422 Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 1 Apr 2010 19:30:21 +0200 Subject: [PATCH 08/16] apply nibble patch removing per-item length limit --- dmenu.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dmenu.c b/dmenu.c index 4c87d6a..f6552aa 100644 --- a/dmenu.c +++ b/dmenu.c @@ -622,24 +622,31 @@ match(char *pattern) { void readstdin(void) { char *p, buf[1024]; - unsigned int len = 0, max = 0; + unsigned int len = 0, blen = 0, max = 0; Item *i, *new; - i = NULL; + i = 0, p = NULL; while(fgets(buf, sizeof buf, stdin)) { - len = strlen(buf); - if(buf[len-1] == '\n') - buf[--len] = '\0'; - if(!(p = strdup(buf))) - eprint("fatal: could not strdup() %u bytes\n", len); + len += (blen = strlen(buf)); + if(!(p = realloc(p, len))) { + eprint("fatal: could not realloc() %u bytes\n", len); + return; + } + memcpy (p + len - blen, buf, blen); + if (p[len - 1] == '\n') + p[len - 1] = 0; + else if (!feof(stdin)) + continue; if(max < len) { maxname = p; max = len; } + len = 0; if(!(new = (Item *)malloc(sizeof(Item)))) eprint("fatal: could not malloc() %u bytes\n", sizeof(Item)); new->next = new->left = new->right = NULL; new->text = p; + p = NULL; if(!i) allitems = new; else -- 2.20.1 From 3472085f59123384fa99252c195fee31160a7764 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Thu, 1 Apr 2010 21:31:09 +0100 Subject: [PATCH 09/16] commited Connor's sanity patch --- dmenu.c | 83 ++++++++++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 51 deletions(-) diff --git a/dmenu.c b/dmenu.c index f6552aa..97014cc 100644 --- a/dmenu.c +++ b/dmenu.c @@ -118,18 +118,14 @@ calcoffsetsh(void) { return; w = promptw + cmdw + 2 * spaceitem; for(next = curr; next; next=next->right) { - tw = textw(next->text); - if(tw > mw / 3) - tw = mw / 3; + tw = MIN(textw(next->text), mw / 3); w += tw; if(w > mw) break; } w = promptw + cmdw + 2 * spaceitem; for(prev = curr; prev && prev->left; prev=prev->left) { - tw = textw(prev->left->text); - if(tw > mw / 3) - tw = mw / 3; + tw = MIN(textw(prev->left->text), mw / 3); w += tw; if(w > mw) break; @@ -138,20 +134,20 @@ calcoffsetsh(void) { void calcoffsetsv(void) { - static unsigned int w; + static unsigned int h; if(!curr) return; - w = (dc.font.height + 2) * (lines + 1); + h = (dc.font.height + 2) * (lines + 1); for(next = curr; next; next=next->right) { - w -= dc.font.height + 2; - if(w <= 0) + h -= dc.font.height + 2; + if(h <= 0) break; } - w = (dc.font.height + 2) * (lines + 1); + h = (dc.font.height + 2) * (lines + 1); for(prev = curr; prev && prev->left; prev=prev->left) { - w -= dc.font.height + 2; - if(w <= 0) + h -= dc.font.height + 2; + if(h <= 0) break; } } @@ -352,10 +348,8 @@ initfont(const char *fontstr) { font_extents = XExtentsOfFontSet(dc.font.set); n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { - if(dc.font.ascent < (*xfonts)->ascent) - dc.font.ascent = (*xfonts)->ascent; - if(dc.font.descent < (*xfonts)->descent) - dc.font.descent = (*xfonts)->descent; + dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); + dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent); xfonts++; } } @@ -396,16 +390,16 @@ kpress(XKeyEvent * e) { return; case XK_a: case XK_A: - cursor = 0; - break; - case XK_e: - case XK_E: - cursor = strlen(text); + ksym = XK_Home; break; case XK_c: case XK_C: ksym = XK_Escape; break; + case XK_e: + case XK_E: + ksym = XK_End; + break; case XK_h: case XK_H: ksym = XK_BackSpace; @@ -429,7 +423,7 @@ kpress(XKeyEvent * e) { i = cursor; while(i-- > 0 && text[i] == ' '); while(i-- > 0 && text[i] != ' '); - memmove(text + i + 1, text + cursor, sizeof text - cursor); + memmove(text + i + 1, text + cursor, sizeof text - cursor + 1); cursor = i + 1; match(text); } @@ -460,12 +454,12 @@ kpress(XKeyEvent * e) { case XK_p: { FILE *fp; - char *c; + char *s; if(!(fp = (FILE*)popen("sselp", "r"))) eprint("dmenu: Could not popen sselp\n"); - c = fgets(buf, sizeof buf, fp); + s = fgets(buf, sizeof buf, fp); pclose(fp); - if(c == NULL) + if(s == NULL) return; } num = strlen(buf); @@ -621,32 +615,25 @@ match(char *pattern) { void readstdin(void) { - char *p, buf[1024]; - unsigned int len = 0, blen = 0, max = 0; + char *p, buf[sizeof text]; + unsigned int len = 0, max = 0; Item *i, *new; - i = 0, p = NULL; + i = NULL; while(fgets(buf, sizeof buf, stdin)) { - len += (blen = strlen(buf)); - if(!(p = realloc(p, len))) { - eprint("fatal: could not realloc() %u bytes\n", len); - return; - } - memcpy (p + len - blen, buf, blen); - if (p[len - 1] == '\n') - p[len - 1] = 0; - else if (!feof(stdin)) - continue; + len = strlen(buf); + if(buf[len-1] == '\n') + buf[--len] = '\0'; + if(!(p = strdup(buf))) + eprint("fatal: could not strdup() %u bytes\n", len); if(max < len) { maxname = p; max = len; } - len = 0; if(!(new = (Item *)malloc(sizeof(Item)))) eprint("fatal: could not malloc() %u bytes\n", sizeof(Item)); new->next = new->left = new->right = NULL; new->text = p; - p = NULL; if(!i) allitems = new; else @@ -812,8 +799,8 @@ main(int argc, char *argv[]) { else if(!strcmp(argv[i], "-v")) eprint("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n"); else - eprint("usage: dmenu [-i] [-b] [-l ] [-fn ] [-nb ] [-nf ]\n" - " [-p ] [-sb ] [-sf ] [-v]\n"); + eprint("usage: dmenu [-i] [-b] [-e ] [-l ] [-fn ] [-nb ]\n" + " [-nf ] [-p ] [-sb ] [-sf ] [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); if(!(dpy = XOpenDisplay(NULL))) @@ -822,14 +809,8 @@ main(int argc, char *argv[]) { if(!root) root = RootWindow(dpy, screen); - if(isatty(STDIN_FILENO)) { - readstdin(); - running = grabkeyboard(); - } - else { /* prevent keypress loss */ - running = grabkeyboard(); - readstdin(); - } + readstdin(); + running = grabkeyboard(); setup(topbar); drawmenu(); -- 2.20.1 From ebeb4e4752e33e9a87cbe0725f65595cba0037fa Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Thu, 1 Apr 2010 21:32:06 +0100 Subject: [PATCH 10/16] added Connor to LICENSE file --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index 1f2db9b..7cd31db 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT/X Consortium License +© 2010 Connor Lane Smith © 2006-2009 Anselm R. Garbe © 2009 Gottox © 2009 Markus Schnalke -- 2.20.1 From 0ba3bae98196ec8a0887f494cb8a2dd5b645f763 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Thu, 1 Apr 2010 21:40:11 +0100 Subject: [PATCH 11/16] applied Troels' patch, thanks Troels! --- dmenu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index 97014cc..fbbfac0 100644 --- a/dmenu.c +++ b/dmenu.c @@ -658,6 +658,10 @@ run(void) { if(ev.xexpose.count == 0) drawmenu(); break; + case VisibilityNotify: + if (ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; } } @@ -691,7 +695,7 @@ setup(Bool topbar) { /* menu window */ wa.override_redirect = True; wa.background_pixmap = ParentRelative; - wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask; + wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | VisibilityChangeMask; /* menu window geometry */ mh = dc.font.height + 2; -- 2.20.1 From e3623cd7f24af660ef2b8cce89a232495d654237 Mon Sep 17 00:00:00 2001 From: Connor Lane Smith Date: Wed, 7 Apr 2010 16:15:34 +0000 Subject: [PATCH 12/16] fixed 3 bugs and some inconsistency --- dmenu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dmenu.c b/dmenu.c index fbbfac0..15a6152 100644 --- a/dmenu.c +++ b/dmenu.c @@ -159,12 +159,12 @@ cistrstr(const char *s, const char *sub) { if(!sub) return (char *)s; - if((c = *sub++) != 0) { + if((c = *sub++) != '\0') { c = tolower(c); len = strlen(sub); do { do { - if((csub = *s++) == 0) + if((csub = *s++) == '\0') return NULL; } while(tolower(csub) != c); @@ -220,7 +220,7 @@ drawmenu(void) { dc.x += promptw; dc.w = mw - promptw; /* print command */ - if(cmdw && item) + if(cmdw && item && !vlist) dc.w = cmdw; drawtext(text[0] ? text : NULL, dc.norm); drawcursor(); @@ -371,7 +371,7 @@ kpress(XKeyEvent * e) { KeySym ksym; len = strlen(text); - buf[0] = 0; + buf[0] = '\0'; num = XLookupString(e, buf, sizeof buf, &ksym, NULL); if(IsKeypadKey(ksym)) { if(ksym == XK_KP_Enter) @@ -414,7 +414,8 @@ kpress(XKeyEvent * e) { break; case XK_u: case XK_U: - text[0] = 0; + cursor = 0; + text[0] = '\0'; match(text); break; case XK_w: @@ -626,7 +627,7 @@ readstdin(void) { buf[--len] = '\0'; if(!(p = strdup(buf))) eprint("fatal: could not strdup() %u bytes\n", len); - if(max < len) { + if(max < len || !maxname) { maxname = p; max = len; } @@ -740,7 +741,7 @@ setup(Bool topbar) { cmdw = MIN(textw(maxname), mw / 3); if(prompt) promptw = MIN(textw(prompt), mw / 5); - text[0] = 0; + text[0] = '\0'; match(text); XMapRaised(dpy, win); } -- 2.20.1 From 09db46f54fa671728498e14e8711b20301b266b7 Mon Sep 17 00:00:00 2001 From: Connor Lane Smith Date: Tue, 13 Apr 2010 20:14:45 +0000 Subject: [PATCH 13/16] fixed ^U cursor support --- dmenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index 15a6152..9f29c19 100644 --- a/dmenu.c +++ b/dmenu.c @@ -414,8 +414,8 @@ kpress(XKeyEvent * e) { break; case XK_u: case XK_U: + memmove(text, text + cursor, sizeof text - cursor + 1); cursor = 0; - text[0] = '\0'; match(text); break; case XK_w: -- 2.20.1 From 518c9b72d1c84bde7de49c2fb04c0d0a7cbe725b Mon Sep 17 00:00:00 2001 From: Connor Lane Smith Date: Wed, 14 Apr 2010 17:35:19 +0000 Subject: [PATCH 14/16] fixed bad parenting, simpler vlist --- dmenu.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/dmenu.c b/dmenu.c index 9f29c19..f93407d 100644 --- a/dmenu.c +++ b/dmenu.c @@ -91,11 +91,10 @@ static Item *sel = NULL; static Item *next = NULL; static Item *prev = NULL; static Item *curr = NULL; -static Window root, win; +static Window parent, win; static int (*fstrncmp)(const char *, const char *, size_t n) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; -static Bool vlist = False; -static unsigned int lines = 5; +static unsigned int lines = 0; static void (*calcoffsets)(void) = calcoffsetsh; void @@ -220,13 +219,12 @@ drawmenu(void) { dc.x += promptw; dc.w = mw - promptw; /* print command */ - if(cmdw && item && !vlist) + if(cmdw && item && lines == 0) dc.w = cmdw; drawtext(text[0] ? text : NULL, dc.norm); drawcursor(); - dc.x += cmdw; if(curr) { - if(vlist) + if(lines > 0) drawmenuv(); else drawmenuh(); @@ -239,8 +237,9 @@ void drawmenuh(void) { Item *i; + dc.x += cmdw; dc.w = spaceitem; - drawtext((curr && curr->left) ? "<" : NULL, dc.norm); + drawtext(curr->left ? "<" : NULL, dc.norm); dc.x += dc.w; /* determine maximum items */ for(i = curr; i != next; i=i->right) { @@ -321,7 +320,7 @@ grabkeyboard(void) { unsigned int len; for(len = 1000; len; len--) { - if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) + if(XGrabKeyboard(dpy, parent, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) break; usleep(1000); @@ -675,6 +674,7 @@ setup(Bool topbar) { #endif XModifierKeymap *modmap; XSetWindowAttributes wa; + XWindowAttributes pwa; /* init modifier map */ modmap = XGetModifierMapping(dpy); @@ -699,16 +699,15 @@ setup(Bool topbar) { wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | VisibilityChangeMask; /* menu window geometry */ - mh = dc.font.height + 2; - mh = vlist ? mh * (lines+1) : mh; + mh = (dc.font.height + 2) * (lines + 1); #if XINERAMA - if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { + if(parent == RootWindow(dpy, screen) && XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { i = 0; if(n > 1) { int di; unsigned int dui; Window dummy; - if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) + if(XQueryPointer(dpy, parent, &dummy, &dummy, &x, &y, &di, &di, &dui)) for(i = 0; i < n; i++) if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) break; @@ -721,19 +720,20 @@ setup(Bool topbar) { else #endif { + XGetWindowAttributes(dpy, parent, &pwa); x = 0; - y = topbar ? 0 : DisplayHeight(dpy, screen) - mh; - mw = DisplayWidth(dpy, screen); + y = topbar ? 0 : pwa.height - mh; + mw = pwa.width; } - win = XCreateWindow(dpy, root, x, y, mw, mh, 0, + win = XCreateWindow(dpy, parent, x, y, mw, mh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); /* pixmap */ - dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, root, 0, NULL); + dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, parent, 0, NULL); XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); if(!dc.font.set) XSetFont(dpy, dc.gc, dc.font.xfont->fid); @@ -776,10 +776,9 @@ main(int argc, char *argv[]) { else if(!strcmp(argv[i], "-b")) topbar = False; else if(!strcmp(argv[i], "-e")) { - if(++i < argc) root = atoi(argv[i]); + if(++i < argc) parent = atoi(argv[i]); } else if(!strcmp(argv[i], "-l")) { - vlist = True; calcoffsets = calcoffsetsv; if(++i < argc) lines = atoi(argv[i]); } @@ -811,8 +810,8 @@ main(int argc, char *argv[]) { if(!(dpy = XOpenDisplay(NULL))) eprint("dmenu: cannot open display\n"); screen = DefaultScreen(dpy); - if(!root) - root = RootWindow(dpy, screen); + if(!parent) + parent = RootWindow(dpy, screen); readstdin(); running = grabkeyboard(); -- 2.20.1 From a6835349dfeafb994f250fcf98acc6dd74f010c2 Mon Sep 17 00:00:00 2001 From: Connor Lane Smith Date: Sun, 2 May 2010 23:17:02 +0100 Subject: [PATCH 15/16] cleaning up --- dmenu.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/dmenu.c b/dmenu.c index f93407d..1762dba 100644 --- a/dmenu.c +++ b/dmenu.c @@ -212,12 +212,12 @@ drawmenu(void) { dc.h = mh; drawtext(NULL, dc.norm); /* print prompt? */ - if(promptw) { + if(prompt) { dc.w = promptw; drawtext(prompt, dc.sel); + dc.x += dc.w; } - dc.x += promptw; - dc.w = mw - promptw; + dc.w = mw - dc.x; /* print command */ if(cmdw && item && lines == 0) dc.w = cmdw; @@ -241,14 +241,13 @@ drawmenuh(void) { dc.w = spaceitem; drawtext(curr->left ? "<" : NULL, dc.norm); dc.x += dc.w; - /* determine maximum items */ for(i = curr; i != next; i=i->right) { dc.w = MIN(textw(i->text), mw / 3); drawtext(i->text, (sel == i) ? dc.sel : dc.norm); dc.x += dc.w; } - dc.x = mw - spaceitem; dc.w = spaceitem; + dc.x = mw - dc.w; drawtext(next ? ">" : NULL, dc.norm); } @@ -259,7 +258,6 @@ drawmenuv(void) { dc.x = 0; dc.w = mw; dc.y += dc.font.height + 2; - /* determine maximum items */ for(i = curr; i != next; i=i->right) { drawtext(i->text, (sel == i) ? dc.sel : dc.norm); dc.y += dc.font.height + 2; @@ -340,13 +338,11 @@ initfont(const char *fontstr) { if(missing) XFreeStringList(missing); if(dc.font.set) { - XFontSetExtents *font_extents; XFontStruct **xfonts; char **font_names; dc.font.ascent = dc.font.descent = 0; - font_extents = XExtentsOfFontSet(dc.font.set); n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); - for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { + for(i = 0; i < n; i++) { dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent); xfonts++; -- 2.20.1 From 5bc288b2b1270957baab2142e1e8b20b796fed11 Mon Sep 17 00:00:00 2001 From: Connor Lane Smith Date: Wed, 5 May 2010 11:42:39 +0100 Subject: [PATCH 16/16] fixed vlist alignment --- dmenu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dmenu.c b/dmenu.c index 1762dba..bebc206 100644 --- a/dmenu.c +++ b/dmenu.c @@ -255,8 +255,7 @@ void drawmenuv(void) { Item *i; - dc.x = 0; - dc.w = mw; + dc.w = mw - dc.x; dc.y += dc.font.height + 2; for(i = curr; i != next; i=i->right) { drawtext(i->text, (sel == i) ? dc.sel : dc.norm); -- 2.20.1