Hi, I wrote two patches for displaying a vertical list and adjusting width/height/offsets of a dmenu-window.
This is how it looks like http://img246.imageshack.us/my.php?image=dmenuvd1.png The first patch just adds the vertical list and a counter option. This counter option is used to display the number off items in the item-list after applying a filter. [-l <#items>] activates vertical list mode, window will be adjusted for displaying #items [-c] displays a counter in vlist mode (hits on applied filter) The second patch adds the options for chaning width/height/offsets. It also adds an option for aligning the window to the right side. [-r] align right [-w <width>] window width. be careful ;( [-h <height>] window height. you can breath a wish here, [-h] has higher priority then [-l] but it gets recalculated internally ( simplified: #items = height / font.height ) [-bo <width>] border width; not a real border but the distance to the edges of the screen. the distance can be also chosen independently: [-x <xoffset>] distance to left or right side of the screen, depends on [-r] [-y <yoffset>] distance to top or bottom of the screen, depends on [-b] [-bo],[-x] and [-y] can be mixed. [-r] and [-b] should work with all of those width/height/offset options. For now it is not checked, if given values for width/offsets are appropriate. Let me know if you have suggestions or comments Frederik --- dmenu-3.8.orig/dmenu.c 2008-08-25 15:34:19.000000000 +0200 +++ dmenu-3.8-vlist/dmenu.c 2008-08-25 16:44:51.000000000 +0200 @@ -47,10 +47,13 @@ /* 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 updatemenuv(Bool); static void drawtext(const char *text, unsigned long col[ColLast]); static void eprint(const char *errstr, ...); static unsigned long getcolor(const char *colstr); @@ -60,7 +63,7 @@ static void match(char *pattern); static void readstdin(void); static void run(void); -static void setup(Bool topbar); +static void setup(void); static int textnw(const char *text, unsigned int len); static int textw(const char *text); @@ -70,13 +73,19 @@ static char *maxname = NULL; static char *prompt = NULL; static char text[4096]; +static char hitstxt[16] = {0}; static int cmdw = 0; static int promptw = 0; static int ret = 0; static int screen; static unsigned int mw, mh; static unsigned int numlockmask = 0; +static unsigned int hits = 0; +static unsigned int lines = 3; static Bool running = True; +static Bool topbar = True; +static Bool vlist = False; +static Bool hitcounter = False; static Display *dpy; static DC dc = {0}; static Item *allitems = NULL; /* first of all items */ @@ -88,6 +97,8 @@ static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t n) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; +static void (*calcoffsets)(void) = calcoffsetsh; +static void (*drawmenu)(void) = drawmenuh; void appenditem(Item *i, Item **list, Item **last) { @@ -98,12 +109,13 @@ i->left = *last; i->right = NULL; *last = i; + ++hits; } void -calcoffsets(void) { - int tw; - unsigned int w; +calcoffsetsh(void) { + static int tw; + static unsigned int w; if(!curr) return; @@ -127,6 +139,26 @@ } } +void +calcoffsetsv(void) { + static unsigned int w; + + if(!curr) + return; + w = (dc.font.height + 2) * (lines - 2); + for(next = curr; next; next=next->right) { + w -= dc.font.height + 2; + if (w <= 0) + break; + } + w = (dc.font.height + 2) * (lines - 2); + 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,8 +203,8 @@ } void -drawmenu(void) { - Item *i; +drawmenuh(void) { + static Item *i; dc.x = 0; dc.y = 0; @@ -212,6 +244,79 @@ } void +drawmenuv(void) { + static Item *i; + + dc.x = 0; + dc.y = 0; + 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 - (hitcounter ? textnw(hitstxt, strlen(hitstxt)) : 0); + + drawtext(text[0] ? text : NULL, dc.norm); + if(curr) { + if (hitcounter) { + dc.w = textw(hitstxt); + dc.x = mw - textw(hitstxt); + drawtext(hitstxt, dc.norm); + } + dc.x = 0; + dc.y = dc.font.height + 2; + dc.w = mw; + drawtext((curr && curr->left) ? "^" : NULL, 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(next ? "v" : NULL, dc.norm); + } else { + if (hitcounter) { + dc.w = textw(hitstxt); + dc.x = mw - textw(hitstxt); + dc.y = 0; + drawtext(hitstxt, dc.norm); + } + dc.x = 0; + dc.w = mw; + dc.h = mh; + 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 +updatemenuv(Bool updown) { + static Item *i; + + if(curr) { + dc.x = 0; + dc.y = (dc.font.height + 2) * 2; + dc.w = mw; + dc.h = mh; + for(i = curr; i != next; i=i->right) { + if (((i==sel->left) && !updown) || (i==sel) + || ((i==sel->right) && updown)) { + drawtext(i->text, (sel == i) ? dc.sel : dc.norm); + XCopyArea(dpy, dc.drawable, win, dc.gc, dc.x, dc.y, + dc.w, (dc.font.height) + 2, dc.x, dc.y); + } + dc.y += dc.font.height + 2; + } + } + XFlush(dpy); +} + +void drawtext(const char *text, unsigned long col[ColLast]) { int x, y, w, h; static char buf[256]; @@ -228,8 +333,8 @@ len = sizeof buf - 1; memcpy(buf, text, len); buf[len] = 0; - 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 */ while(len && (w = textnw(buf, len)) > dc.w - h) @@ -446,12 +551,18 @@ calcoffsets(); break; case XK_Left: + case XK_Up: if(!(sel && sel->left)) return; sel=sel->left; if(sel->right == curr) { curr = prev; calcoffsets(); + } else { + if (vlist) { + updatemenuv(True); + return; + } } break; case XK_Next: @@ -477,12 +588,18 @@ running = False; break; case XK_Right: + case XK_Down: if(!(sel && sel->right)) return; sel=sel->right; if(sel == next) { curr = next; calcoffsets(); + } else { + if (vlist) { + updatemenuv(False); + return; + } } break; case XK_Tab: @@ -534,6 +651,8 @@ } curr = prev = next = sel = item; calcoffsets(); + snprintf(hitstxt, sizeof(hitstxt), "(%d)", hits); + hits = 0; } void @@ -585,7 +704,7 @@ } void -setup(Bool topbar) { +setup(void) { int i, j, x, y; #if XINERAMA int n; @@ -643,6 +762,11 @@ mw = DisplayWidth(dpy, screen); } + /* update menu window geometry */ + + mh = vlist ? (dc.font.height + 2) * lines : mh; + y = topbar ? y : y - mh + (dc.font.height + 2); + win = XCreateWindow(dpy, root, x, y, mw, mh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), @@ -686,7 +810,6 @@ int main(int argc, char *argv[]) { unsigned int i; - Bool topbar = True; /* command line args */ for(i = 1; i < argc; i++) @@ -696,6 +819,14 @@ } 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], "-c")) + hitcounter = True; else if(!strcmp(argv[i], "-fn")) { if(++i < argc) font = argv[i]; } @@ -717,8 +848,8 @@ else if(!strcmp(argv[i], "-v")) eprint("dmenu-"VERSION", © 2006-2008 dmenu engineers, see LICENSE for details\n"); else - eprint("usage: dmenu [-i] [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n" - " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n"); + eprint("usage: dmenu [-i] [-b] [-l <#items>] [-c] [-fn <font>] [-nb <color>]\n" + "[-nf <color>] [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); if(!(dpy = XOpenDisplay(0))) @@ -735,7 +866,7 @@ readstdin(); } - setup(topbar); + setup(); drawmenu(); XSync(dpy, False); run(); -- Frederik Schiewek <[EMAIL PROTECTED]>
