Hi folks,

I keep a file containing a list of gui applications to pipe into dmenu, 
so that I could only start those applications that do make sense in the 
graphical environment.

However, since vanilla dmenu allows to insert any arbitrary text, this 
isn't fool-proof, I could still type "dd" hit Return and fork a running 
program that never stops until I kill it (please don't tell me, that 
this is a human problem and should not yield to patch dmenu).

The attached simplechoice patch adds the command line switch '-c', which
causes dmenu to only allow selecting one of the given entries. It does 
still work as normal, i.e. typing text results in filtering out the 
not-matching entries.

It's also useful in other cases, for example to select a bookmark to 
open in surf. So it might be useful to others, which is why I'm mailing 
it to the list...


Bert
diff -rup dmenu-4.2.1-orig/dmenu.1 dmenu-4.2.1/dmenu.1
--- dmenu-4.2.1-orig/dmenu.1    2010-11-20 10:24:33.000000000 +0100
+++ dmenu-4.2.1/dmenu.1 2011-01-01 16:20:12.000000000 +0100
@@ -4,6 +4,7 @@ dmenu \- dynamic menu
 .SH SYNOPSIS
 .B dmenu
 .RB [ \-b ]
+.RB [ \-c ]
 .RB [ \-i ]
 .RB [ \-l
 .IR lines ]
@@ -47,6 +48,9 @@ is a program used by dmenu_run to find a
 .B \-b
 dmenu appears at the bottom of the screen.
 .TP
+.B \-c
+dmenu only allows selecting one of the given menu items.
+.TP
 .B \-i
 dmenu matches menu items case insensitively.
 .TP
diff -rup dmenu-4.2.1-orig/dmenu.c dmenu-4.2.1/dmenu.c
--- dmenu-4.2.1-orig/dmenu.c    2011-01-01 15:08:49.000000000 +0100
+++ dmenu-4.2.1/dmenu.c 2011-01-02 13:40:11.000000000 +0100
@@ -55,6 +55,7 @@ static unsigned long normcol[ColLast];
 static unsigned long selcol[ColLast];
 static Atom utf8;
 static Bool topbar = True;
+static Bool choice = False;
 static DC *dc;
 static Item *items = NULL;
 static Item *matches, *sel;
@@ -76,6 +77,8 @@ main(int argc, char *argv[]) {
                }
                else if(!strcmp(argv[i], "-b"))
                        topbar = False;
+               else if(!strcmp(argv[i], "-c"))
+                       choice = True;
                else if(!strcmp(argv[i], "-i"))
                        fstrncmp = strncasecmp;
                else if(i == argc-1)
@@ -152,12 +155,19 @@ drawmenu(void) {
                drawtext(dc, prompt, selcol);
                dc->x = dc->w;
        }
-       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));
+       if(!choice) {
+               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));
+       }
 
        if(lines > 0) {
+               if(choice) {
+                       if(prompt)
+                               dc->x += 8;
+                       dc->y = -dc->h;
+               }
                dc->w = mw - dc->x;
                for(item = curr; item != next; item = item->right) {
                        dc->y += dc->h;
@@ -255,6 +265,8 @@ keypress(XKeyEvent *ev) {
                        ksym = XK_Return;
                        break;
                case XK_k:  /* delete right */
+                       if(choice)
+                               return;
                        text[cursor] = '\0';
                        match();
                        break;
@@ -268,6 +280,8 @@ keypress(XKeyEvent *ev) {
                        insert(NULL, 0 - cursor);
                        break;
                case XK_w:  /* delete word */
+                       if(choice)
+                               return;
                        while(cursor > 0 && text[nextrune(-1)] == ' ')
                                insert(NULL, nextrune(-1) - cursor);
                        while(cursor > 0 && text[nextrune(-1)] != ' ')
@@ -292,7 +306,7 @@ keypress(XKeyEvent *ev) {
                        insert(NULL, nextrune(-1) - cursor);
                break;
        case XK_End:
-               if(cursor < len) {
+               if(!choice && cursor < len) {
                        cursor = len;
                        break;
                }
@@ -306,7 +320,7 @@ keypress(XKeyEvent *ev) {
        case XK_Escape:
                exit(EXIT_FAILURE);
        case XK_Home:
-               if(sel == matches) {
+               if(!choice && sel == matches) {
                        cursor = 0;
                        break;
                }
@@ -314,7 +328,7 @@ keypress(XKeyEvent *ev) {
                calcoffsets();
                break;
        case XK_Left:
-               if(cursor > 0 && (!sel || !sel->left || lines > 0)) {
+               if(!choice && cursor > 0 && (!sel || !sel->left || lines > 0)) {
                        cursor = nextrune(-1);
                        break;
                }
@@ -340,11 +354,14 @@ keypress(XKeyEvent *ev) {
                break;
        case XK_Return:
        case XK_KP_Enter:
-               fputs((sel && !(ev->state & ShiftMask)) ? sel->text : text, 
stdout);
+               if(choice)
+                       fputs(sel ? sel->text : "", stdout);
+               else
+                       fputs((sel && !(ev->state & ShiftMask)) ? sel->text : 
text, stdout);
                fflush(stdout);
                exit(EXIT_SUCCESS);
        case XK_Right:
-               if(cursor < len) {
+               if(!choice && cursor < len) {
                        cursor = nextrune(+1);
                        break;
                }
@@ -357,7 +374,7 @@ keypress(XKeyEvent *ev) {
                }
                break;
        case XK_Tab:
-               if(!sel)
+               if(choice || !sel)
                        return;
                strncpy(text, sel->text, sizeof text);
                cursor = strlen(text);
@@ -443,7 +460,8 @@ readstdin(void) {
                if(!(item->text = strdup(buf)))
                        eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
                item->next = item->left = item->right = NULL;
-               inputw = MAX(inputw, textw(dc, item->text));
+               if(!choice)
+                       inputw = MAX(inputw, textw(dc, item->text));
        }
 }
 
@@ -492,7 +510,10 @@ setup(void) {
        /* menu geometry */
        bh = dc->font.height + 2;
        lines = MAX(lines, 0);
-       mh = (lines + 1) * bh;
+       if(choice && lines > 0)
+               mh = lines * bh;
+       else
+               mh = (lines + 1) * bh;
 #ifdef XINERAMA
        if((info = XineramaQueryScreens(dc->dpy, &n))) {
                int i, di;

Reply via email to