[dwm] [dmenu] [patch] [1] vertical list

From: Frederik Schiewek <fs_AT_schiewek.net>
Date: Mon, 25 Aug 2008 20:57:19 +0200

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 <fs_AT_schiewek.net>
Received on Mon Aug 25 2008 - 18:57:19 UTC

This archive was generated by hypermail 2.2.0 : Mon Aug 25 2008 - 19:12:04 UTC