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]>

Reply via email to