tfixed bugs, no more config.h, updated manpage, new libdraw - dmenu - Dmenu fork with xft fonts.
 (HTM) git clone git://r-36.net/dmenu
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit a7aee433ccfd2590e0785a7b93a89d8d0593a234
 (DIR) parent a3606ecb0eeaffa752fdf26565ebaaba29b83239
 (HTM) Author: Connor Lane Smith <cls@lubutu.com>
       Date:   Mon,  2 Aug 2010 14:22:54 +0100
       
       fixed bugs, no more config.h, updated manpage, new libdraw
       Diffstat:
         Makefile                            |      24 ++++++++----------------
         README                              |      11 ++++++-----
         config.def.h                        |       8 --------
         config.mk                           |      17 +++++++----------
         dmenu.1                             |      98 +++++++++++++++----------------
         dmenu.c                             |     222 +++++++++++++------------------
         dmenu_path                          |       2 +-
       
       7 files changed, 162 insertions(+), 220 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -3,9 +3,6 @@
        
        include config.mk
        
       -SRC = dmenu.c
       -OBJ = ${SRC:.c=.o}
       -
        all: options dmenu
        
        options:
       t@@ -14,34 +11,28 @@ options:
                @echo "LDFLAGS  = ${LDFLAGS}"
                @echo "CC       = ${CC}"
        
       -.c.o:
       +dmenu.o: dmenu.c config.mk
                @echo CC $<
                @${CC} -c ${CFLAGS} $<
        
       -${OBJ}: config.h config.mk
       -
       -config.h:
       -        @echo creating $@ from config.def.h
       -        @cp config.def.h $@
       -
       -dmenu: ${OBJ}
       +dmenu: dmenu.o
                @echo CC -o $@
                @${CC} -o $@ $+ ${LDFLAGS}
        
        clean:
                @echo cleaning
       -        @rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
       +        @rm -f dmenu dmenu.o dmenu-${VERSION}.tar.gz
        
        dist: clean
                @echo creating dist tarball
                @mkdir -p dmenu-${VERSION}
       -        @cp -R LICENSE Makefile README config.mk dmenu.1 config.def.h dmenu_path dmenu_run ${SRC} dmenu-${VERSION}
       +        @cp -R LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path dmenu_run dmenu-${VERSION}
                @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
                @gzip dmenu-${VERSION}.tar
                @rm -rf dmenu-${VERSION}
        
        install: all
       -        @echo installing executable file to ${DESTDIR}${PREFIX}/bin
       +        @echo installing executables to ${DESTDIR}${PREFIX}/bin
                @mkdir -p ${DESTDIR}${PREFIX}/bin
                @cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
                @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
       t@@ -53,8 +44,9 @@ install: all
                @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1
        
        uninstall:
       -        @echo removing executable file from ${DESTDIR}${PREFIX}/bin
       -        @rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
       +        @echo removing executables from ${DESTDIR}${PREFIX}/bin
       +        @rm -f ${DESTDIR}${PREFIX}/bin/dmenu
       +        @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path
                @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
                @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
                @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
 (DIR) diff --git a/README b/README
       t@@ -1,21 +1,22 @@
        dmenu - dynamic menu
        ====================
       -dmenu is a generic and efficient menu for X. 
       +dmenu is an efficient dynamic menu for X.
        
        
        Requirements
        ------------
        In order to build dmenu you need the Xlib header files.
       +
        You also need libdraw, available from http://hg.suckless.org/libdraw
        
        
        Installation
        ------------
       -Edit config.mk to match your local setup (dmenu is installed into the
       -/usr/local namespace by default).
       +Edit config.mk to match your local setup (dmenu is installed into
       +the /usr/local namespace by default).
        
       -Afterwards enter the following command to build and install dmenu (if
       -necessary as root):
       +Afterwards enter the following command to build and install dmenu
       +(if necessary as root):
        
            make clean install
        
 (DIR) diff --git a/config.def.h b/config.def.h
       t@@ -1,8 +0,0 @@
       -/* See LICENSE file for copyright and license details. */
       -
       -/* appearance */
       -static const char *font        = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
       -static const char *normbgcolor = "#cccccc";
       -static const char *normfgcolor = "#000000";
       -static const char *selbgcolor  = "#0066ff";
       -static const char *selfgcolor  = "#ffffff";
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -1,5 +1,5 @@
        # dmenu version
       -VERSION = 4.1.1
       +VERSION = 4.2
        
        # Customize below to fit your system
        
       t@@ -7,25 +7,22 @@ VERSION = 4.1.1
        PREFIX = /usr/local
        MANPREFIX = ${PREFIX}/share/man
        
       +# Xlib
        X11INC = /usr/X11R6/include
        X11LIB = /usr/X11R6/lib
        
        # Xinerama, comment if you don't want it
       -XINERAMALIBS = -L${X11LIB} -lXinerama
       +XINERAMALIBS  = -lXinerama
        XINERAMAFLAGS = -DXINERAMA
        
        # includes and libs
       -INCS = -I. -I/usr/include -I${X11INC}
       -LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -ldraw ${XINERAMALIBS}
       +INCS = -I${X11INC}
       +LIBS = -L${X11LIB} -ldraw -lX11 ${XINERAMALIBS}
        
        # flags
        CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
       -CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
       -LDFLAGS = -s ${LIBS}
       -
       -# Solaris
       -#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
       -#LDFLAGS = ${LIBS}
       +CFLAGS   = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
       +LDFLAGS  = -s ${LIBS}
        
        # compiler and linker
        CC = cc
 (DIR) diff --git a/dmenu.1 b/dmenu.1
       t@@ -5,81 +5,76 @@ dmenu \- dynamic menu
        .B dmenu
        .RB [ \-b ]
        .RB [ \-i ]
       -.RB [ \-l " <lines>]"
       -.RB [ \-p " <prompt>]"
       -.RB [ \-fn " <font>]"
       -.RB [ \-nb " <color>]"
       -.RB [ \-nf " <color>]"
       -.RB [ \-sb " <color>]"
       -.RB [ \-sf " <color>]"
       +.RB [ \-l
       +.IR lines ]
       +.RB [ \-p
       +.IR prompt ]
       +.RB [ \-fn
       +.IR font ]
       +.RB [ \-nb
       +.IR color ]
       +.RB [ \-nf
       +.IR color ]
       +.RB [ \-sb
       +.IR color ]
       +.RB [ \-sf
       +.IR color ]
        .RB [ \-v ]
       -
       -.B dmenu_run
       -.RB [ \-b ]
       -.RB [ \-i ]
       -.RB [ \-l " <lines>]"
       -.RB [ \-p " <prompt>]"
       -.RB [ \-fn " <font>]"
       -.RB [ \-nb " <color>]"
       -.RB [ \-nf " <color>]"
       -.RB [ \-sb " <color>]"
       -.RB [ \-sf " <color>]"
       -.RB [ \-v ]
       -
       +.P
       +.BR dmenu_run " ..."
       +.P
        .B dmenu_path
        .SH DESCRIPTION
       -.SS Overview
        .B dmenu
       -is a generic menu for X, originally designed for
       +is a dynamic menu for X, originally designed for
        .BR dwm (1).
       -It manages huge amounts (10000 and more) of user defined menu items efficiently.
       +It manages huge numbers of user-defined menu items efficiently.
       +.P
       +dmenu reads a list of newline-separated items from standard input and creates a
       +menu.  When the user selects an item or enters any text and presses Return,
       +their choice is printed to standard output and dmenu terminates.
        .P
        .B dmenu_run
       -is a dmenu script which lists programs in the user's PATH and executes
       -the selected item.
       +is a dmenu script used by dwm which lists programs in the user's PATH and
       +executes the selected item.
        .P
        .B dmenu_path
       -is a script used by
       -.I dmenu_run
       -to find and cache a list of programs.
       -.SS Options
       +is a script used by dmenu_run to find and cache a list of programs.
       +.SH OPTIONS
        .TP
        .B \-b
        dmenu appears at the bottom of the screen.
        .TP
        .B \-i
       -dmenu matches menu entries case insensitively.
       +dmenu matches menu items case insensitively.
        .TP
       -.B \-l <lines>
       +.BI \-l " lines"
        dmenu lists items vertically, with the given number of lines.
        .TP
       -.B \-p <prompt>
       -sets the prompt to be displayed to the left of the input area.
       +.BI \-p " prompt"
       +defines the prompt to be displayed to the left of the input area.
        .TP
       -.B \-fn <font>
       -sets the font.
       +.BI \-fn " font"
       +defines the font set used.
        .TP
       -.B \-nb <color>
       -sets the background color (#RGB, #RRGGBB, and color names are supported).
       +.BI \-nb " color"
       +defines the normal background color.
       +.IR #RGB ,
       +.IR #RRGGBB ,
       +and color names are supported.
        .TP
       -.B \-nf <color>
       -sets the foreground color (#RGB, #RRGGBB, and color names are supported).
       +.BI \-nf " color"
       +defines the normal foreground color.
        .TP
       -.B \-sb <color>
       -sets the background color of selected items (#RGB, #RRGGBB, and color names are
       -supported).
       +.BI \-sb " color"
       +defines the selected background color.
        .TP
       -.B \-sf <color>
       -sets the foreground color of selected items (#RGB, #RRGGBB, and color names are
       -supported).
       +.BI \-sf " color"
       +defines the selected foreground color.
        .TP
        .B \-v
        prints version information to standard output, then exits.
        .SH USAGE
       -dmenu reads a list of newline-separated items from standard input and creates a
       -menu.  When the user selects an item or enters any text and presses Return,
       -their choice is printed to standard output and dmenu terminates.
       -.P
        dmenu is completely controlled by the keyboard.  Besides standard Unix line
        editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the
        following keys are recognized:
       t@@ -96,10 +91,9 @@ Confirm input.  Prints the input text to standard output and exits, returning
        success.
        .TP
        .B Escape (Control\-c)
       -Quit without selecting an item, returning failure.
       +Exit without selecting an item, returning failure.
        .TP
        .B Control\-y
        Paste the current X selection into the input field.
        .SH SEE ALSO
       -.BR dwm (1),
       -.BR wmii (1).
       +.BR dwm (1)
 (DIR) diff --git a/dmenu.c b/dmenu.c
       t@@ -1,11 +1,9 @@
        /* See LICENSE file for copyright and license details. */
        #include <ctype.h>
       -#include <locale.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <unistd.h>
       -#include <X11/keysym.h>
        #include <X11/Xatom.h>
        #include <X11/Xlib.h>
        #include <X11/Xutil.h>
       t@@ -13,7 +11,6 @@
        #include <X11/extensions/Xinerama.h>
        #endif
        #include <draw.h>
       -#include "config.h"
        
        #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))
       t@@ -38,25 +35,27 @@ static void grabkeyboard(void);
        static void insert(const char *s, ssize_t n);
        static void keypress(XKeyEvent *e);
        static void match(void);
       -static void paste(Atom atom);
       +static void paste(void);
        static void readstdin(void);
        static void run(void);
        static void setup(void);
        static void usage(void);
        
       -static char *prompt;
        static char text[4096];
       -static int screen;
        static size_t cursor = 0;
       +static const char *prompt = NULL;
       +static const char *normbgcolor = "#cccccc";
       +static const char *normfgcolor = "#000000";
       +static const char *selbgcolor  = "#0066ff";
       +static const char *selfgcolor  = "#ffffff";
        static unsigned int inputw = 0;
        static unsigned int lines = 0;
        static unsigned int mw, mh;
       -static unsigned int promptw = 0;
        static unsigned long normcol[ColLast];
        static unsigned long selcol[ColLast];
        static Atom utf8;
        static Bool topbar = True;
       -static DC dc;
       +static DC *dc;
        static Item *allitems, *matches;
        static Item *curr, *prev, *next, *sel;
        static Window root, win;
       t@@ -67,7 +66,7 @@ static void (*calcoffsets)(void) = calcoffsetsh;
        
        void
        appenditem(Item *item, Item **list, Item **last) {
       -        if(!(*last))
       +        if(!*last)
                        *list = item;
                else
                        (*last)->right = item;
       t@@ -80,12 +79,12 @@ void
        calcoffsetsh(void) {
                unsigned int w, x;
        
       -        w = promptw + inputw + textw(&dc, "<") + textw(&dc, ">");
       +        w = (prompt ? textw(dc, prompt) : 0) + inputw + textw(dc, "<") + textw(dc, ">");
                for(x = w, next = curr; next; next = next->right)
       -                if((x += MIN(textw(&dc, next->text), mw / 3)) > mw)
       +                if((x += MIN(textw(dc, next->text), mw / 3)) > mw)
                                break;
                for(x = w, prev = curr; prev && prev->left; prev = prev->left)
       -                if((x += MIN(textw(&dc, prev->left->text), mw / 3)) > mw)
       +                if((x += MIN(textw(dc, prev->left->text), mw / 3)) > mw)
                                break;
        }
        
       t@@ -96,101 +95,75 @@ calcoffsetsv(void) {
                next = prev = curr;
                for(i = 0; i < lines && next; i++)
                        next = next->right;
       -        mh = (dc.font.height + 2) * (i + 1);
                for(i = 0; i < lines && prev && prev->left; i++)
                        prev = prev->left;
        }
        
        char *
        cistrstr(const char *s, const char *sub) {
       -        int c, csub;
       -        unsigned int len;
       +        size_t len;
        
       -        if(!sub)
       -                return (char *)s;
       -        if((c = tolower(*sub++)) != '\0') {
       -                len = strlen(sub);
       -                do {
       -                        do {
       -                                if((csub = *s++) == '\0')
       -                                        return NULL;
       -                        }
       -                        while(tolower(csub) != c);
       -                }
       -                while(strncasecmp(s, sub, len) != 0);
       -                s--;
       -        }
       -        return (char *)s;
       +        for(len = strlen(sub); *s; s++)
       +                if(!strncasecmp(s, sub, len))
       +                        return (char *)s;
       +        return NULL;
        }
        
        void
        drawmenu(void) {
       -        dc.x = 0;
       -        dc.y = 0;
       -        dc.w = mw;
       -        dc.h = mh;
       -        drawbox(&dc, normcol);
       -        dc.h = dc.font.height + 2;
       -        dc.y = topbar ? 0 : mh - dc.h;
       +        dc->x = 0;
       +        dc->y = 0;
       +        drawrect(dc, 0, 0, mw, mh, BG(dc, normcol));
       +        dc->h = dc->font.height + 2;
       +        dc->y = topbar ? 0 : mh - dc->h;
                /* print prompt? */
                if(prompt) {
       -                dc.w = promptw;
       -                drawbox(&dc, selcol);
       -                drawtext(&dc, prompt, selcol);
       -                dc.x += dc.w;
       +                dc->w = textw(dc, prompt);
       +                drawtext(dc, prompt, selcol);
       +                dc->x = dc->w;
                }
       -        dc.w = mw - dc.x;
       +        dc->w = mw - dc->x;
                /* print input area */
       -        if(matches && lines == 0 && textw(&dc, text) <= inputw)
       -                dc.w = inputw;
       -        drawtext(&dc, text, normcol);
       -        drawline(&dc, textnw(&dc, text, cursor) + dc.h/2 - 2, 2, 1, dc.h-4, normcol);
       +        if(matches && lines == 0 && textw(dc, text) <= inputw)
       +                dc->w = inputw;
       +        drawtext(dc, text, normcol);
       +        drawrect(dc, textnw(dc, text, cursor) + dc->h/2 - 2, 2, 1, dc->h - 4, FG(dc, normcol));
                if(lines > 0)
                        drawmenuv();
       -        else if(curr && (dc.w == inputw || curr->next))
       +        else if(curr && (dc->w == inputw || curr->next))
                        drawmenuh();
       -        commitdraw(&dc, win);
       +        commitdraw(dc, win);
        }
        
        void
        drawmenuh(void) {
                Item *item;
        
       -        dc.x += inputw;
       -        dc.w = textw(&dc, "<");
       +        dc->x += inputw;
       +        dc->w = textw(dc, "<");
                if(curr->left)
       -                drawtext(&dc, "<", normcol);
       -        dc.x += dc.w;
       +                drawtext(dc, "<", normcol);
                for(item = curr; item != next; item = item->right) {
       -                dc.w = MIN(textw(&dc, item->text), mw / 3);
       -                if(item == sel)
       -                        drawbox(&dc, selcol);
       -                drawtext(&dc, item->text, (item == sel) ? selcol : normcol);
       -                dc.x += dc.w;
       +                dc->x += dc->w;
       +                dc->w = MIN(textw(dc, item->text), mw / 3);
       +                drawtext(dc, item->text, (item == sel) ? selcol : normcol);
                }
       -        dc.w = textw(&dc, ">");
       -        dc.x = mw - dc.w;
       +        dc->w = textw(dc, ">");
       +        dc->x = mw - dc->w;
                if(next)
       -                drawtext(&dc, ">", normcol);
       +                drawtext(dc, ">", normcol);
        }
        
        void
        drawmenuv(void) {
                Item *item;
       -        XWindowAttributes wa;
        
       -        dc.y = topbar ? dc.h : 0;
       -        dc.w = mw - dc.x;
       +        dc->y = topbar ? dc->h : 0;
       +        dc->w = mw - dc->x;
                for(item = curr; item != next; item = item->right) {
       -                if(item == sel)
       -                        drawbox(&dc, selcol);
       -                drawtext(&dc, item->text, (item == sel) ? selcol : normcol);
       -                dc.y += dc.h;
       +                drawtext(dc, item->text, (item == sel) ? selcol : normcol);
       +                dc->y += dc->h;
                }
       -        if(!XGetWindowAttributes(dc.dpy, win, &wa))
       -                eprintf("cannot get window attributes\n");
       -        if(wa.height != mh)
       -                XMoveResizeWindow(dc.dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh);
        }
        
        void
       t@@ -198,7 +171,7 @@ grabkeyboard(void) {
                int i;
        
                for(i = 0; i < 1000; i++) {
       -                if(!XGrabKeyboard(dc.dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime))
       +                if(!XGrabKeyboard(dc->dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime))
                                return;
                        usleep(1000);
                }
       t@@ -254,6 +227,7 @@ keypress(XKeyEvent *e) {
                                break;
                        case XK_k:  /* delete right */
                                text[cursor] = '\0';
       +                        match();
                                break;
                        case XK_n:
                                ksym = XK_Down;
       t@@ -270,10 +244,10 @@ keypress(XKeyEvent *e) {
                                n = 0;
                                while(cursor - n++ > 0 && text[cursor - n] == ' ');
                                while(cursor - n++ > 0 && text[cursor - n] != ' ');
       -                        insert(NULL, -(--n));
       +                        insert(NULL, 1-n);
                                break;
                        case XK_y:  /* paste selection */
       -                        XConvertSelection(dc.dpy, XA_PRIMARY, utf8, None, win, CurrentTime);
       +                        XConvertSelection(dc->dpy, XA_PRIMARY, utf8, None, win, CurrentTime);
                                /* causes SelectionNotify event */
                                return;
                        }
       t@@ -348,7 +322,7 @@ keypress(XKeyEvent *e) {
                        break;
                case XK_Return:
                case XK_KP_Enter:
       -                fputs(((e->state & ShiftMask) || sel) ? sel->text : text, stdout);
       +                fputs((sel && !(e->state & ShiftMask)) ? sel->text : text, stdout);
                        fflush(stdout);
                        exit(EXIT_SUCCESS);
                case XK_Right:
       t@@ -418,15 +392,14 @@ match(void) {
        }
        
        void
       -paste(Atom atom)
       -{
       +paste(void) {
                char *p, *q;
                int di;
                unsigned long dl;
                Atom da;
        
       -        XGetWindowProperty(dc.dpy, win, atom, 0, sizeof text - cursor, True,
       -                        utf8, &da, &di, &dl, &dl, (unsigned char **)&p);
       +        XGetWindowProperty(dc->dpy, win, utf8, 0, sizeof text - cursor, True,
       +                           utf8, &da, &di, &dl, &dl, (unsigned char **)&p);
                insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p));
                XFree(p);
                drawmenu();
       t@@ -434,24 +407,22 @@ paste(Atom atom)
        
        void
        readstdin(void) {
       -        char buf[sizeof text];
       -        size_t len;
       +        char buf[sizeof text], *p;
                Item *item, *new;
        
                allitems = NULL;
                for(item = NULL; fgets(buf, sizeof buf, stdin); item = new) {
       -                len = strlen(buf);
       -                if(buf[len-1] == '\n')
       -                        buf[--len] = '\0';
       +                if((p = strchr(buf, '\n')))
       +                        *p = '\0';
                        if(!(new = malloc(sizeof *new)))
                                eprintf("cannot malloc %u bytes\n", sizeof *new);
                        if(!(new->text = strdup(buf)))
       -                        eprintf("cannot strdup %u bytes\n", len);
       -                inputw = MAX(inputw, textw(&dc, new->text));
       +                        eprintf("cannot strdup %u bytes\n", strlen(buf));
       +                inputw = MAX(inputw, textw(dc, new->text));
                        new->next = new->left = new->right = NULL;
                        if(item)
                                item->next = new;
       -                else 
       +                else
                                allitems = new;
                }
        }
       t@@ -460,7 +431,7 @@ void
        run(void) {
                XEvent ev;
        
       -        while(!XNextEvent(dc.dpy, &ev))
       +        while(!XNextEvent(dc->dpy, &ev))
                        switch(ev.type) {
                        case Expose:
                                if(ev.xexpose.count == 0)
       t@@ -470,39 +441,43 @@ run(void) {
                                keypress(&ev.xkey);
                                break;
                        case SelectionNotify:
       -                        if(ev.xselection.property != None)
       -                                paste(ev.xselection.property);
       +                        if(ev.xselection.property == utf8)
       +                                paste();
                                break;
                        case VisibilityNotify:
                                if(ev.xvisibility.state != VisibilityUnobscured)
       -                                XRaiseWindow(dc.dpy, win);
       +                                XRaiseWindow(dc->dpy, win);
                                break;
                        }
        }
        
        void
        setup(void) {
       -        int x, y;
       +        int x, y, screen;
       +        XSetWindowAttributes wa;
        #ifdef XINERAMA
       -        int i, n;
       +        int n;
                XineramaScreenInfo *info;
        #endif
       -        XSetWindowAttributes wa;
        
       -        normcol[ColBG] = getcolor(&dc, normbgcolor);
       -        normcol[ColFG] = getcolor(&dc, normfgcolor);
       -        selcol[ColBG] = getcolor(&dc, selbgcolor);
       -        selcol[ColFG] = getcolor(&dc, selfgcolor);
       +        screen = DefaultScreen(dc->dpy);
       +        root = RootWindow(dc->dpy, screen);
       +        utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False);
       +
       +        normcol[ColBG] = getcolor(dc, normbgcolor);
       +        normcol[ColFG] = getcolor(dc, normfgcolor);
       +        selcol[ColBG] = getcolor(dc, selbgcolor);
       +        selcol[ColFG] = getcolor(dc, selfgcolor);
        
                /* input window geometry */
       -        mh = (dc.font.height + 2) * (lines + 1);
       +        mh = (dc->font.height + 2) * (lines + 1);
        #ifdef XINERAMA
       -        if((info = XineramaQueryScreens(dc.dpy, &n))) {
       -                int di;
       +        if((info = XineramaQueryScreens(dc->dpy, &n))) {
       +                int i, di;
                        unsigned int du;
                        Window dw;
        
       -                XQueryPointer(dc.dpy, root, &dw, &dw, &x, &y, &di, &di, &du);
       +                XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du);
                        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;
       t@@ -515,31 +490,30 @@ setup(void) {
        #endif
                {
                        x = 0;
       -                y = topbar ? 0 : DisplayHeight(dc.dpy, screen) - mh;
       -                mw = DisplayWidth(dc.dpy, screen);
       +                y = topbar ? 0 : DisplayHeight(dc->dpy, screen) - mh;
       +                mw = DisplayWidth(dc->dpy, screen);
                }
        
                /* input window */
                wa.override_redirect = True;
                wa.background_pixmap = ParentRelative;
                wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
       -        win = XCreateWindow(dc.dpy, root, x, y, mw, mh, 0,
       -                        DefaultDepth(dc.dpy, screen), CopyFromParent,
       -                        DefaultVisual(dc.dpy, screen),
       +        win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0,
       +                        DefaultDepth(dc->dpy, screen), CopyFromParent,
       +                        DefaultVisual(dc->dpy, screen),
                                CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
        
       -        match();
                grabkeyboard();
       -        setupdraw(&dc, win);
       -        inputw = MIN(inputw, mw / 3);
       -        utf8 = XInternAtom(dc.dpy, "UTF8_STRING", False);
       -        XMapRaised(dc.dpy, win);
       +        setcanvas(dc, win, mw, mh);
       +        inputw = MIN(inputw, mw/3);
       +        XMapRaised(dc->dpy, win);
       +        match();
        }
        
        void
        usage(void) {
       -        fputs("usage: dmenu [-b] [-i] [-l <lines>] [-p <prompt>] [-fn <font>] [-nb <color>]\n"
       -                      "             [-nf <color>] [-sb <color>] [-sf <color>] [-v]\n", stderr);
       +        fputs("usage: dmenu [-b] [-i] [-l lines] [-p prompt] [-fn font] [-nb color]\n"
       +              "             [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
                exit(EXIT_FAILURE);
        }
        
       t@@ -548,8 +522,10 @@ main(int argc, char *argv[]) {
                int i;
        
                progname = "dmenu";
       +        dc = initdraw();
       +
                for(i = 1; i < argc; i++)
       -                /* 1-arg flags */
       +                /* single flags */
                        if(!strcmp(argv[i], "-v")) {
                                fputs("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n", stdout);
                                exit(EXIT_SUCCESS);
       t@@ -562,17 +538,15 @@ main(int argc, char *argv[]) {
                        }
                        else if(i == argc-1)
                                usage();
       -                /* 2-arg flags */
       +                /* double flags */
                        else if(!strcmp(argv[i], "-l")) {
                                if((lines = atoi(argv[++i])) > 0)
                                        calcoffsets = calcoffsetsv;
                        }
       -                else if(!strcmp(argv[i], "-p")) {
       +                else if(!strcmp(argv[i], "-p"))
                                prompt = argv[++i];
       -                        promptw = MIN(textw(&dc, prompt), mw/5);
       -                }
                        else if(!strcmp(argv[i], "-fn"))
       -                        font = argv[++i];
       +                        initfont(dc, argv[i++]);
                        else if(!strcmp(argv[i], "-nb"))
                                normbgcolor = argv[++i];
                        else if(!strcmp(argv[i], "-nf"))
       t@@ -584,14 +558,6 @@ main(int argc, char *argv[]) {
                        else
                                usage();
        
       -        if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
       -                fputs("dmenu: warning: no locale support\n", stderr);
       -        if(!(dc.dpy = XOpenDisplay(NULL)))
       -                eprintf("cannot open display\n");
       -        screen = DefaultScreen(dc.dpy);
       -        root = RootWindow(dc.dpy, screen);
       -        initfont(&dc, font);
       -
                readstdin();
                setup();
                run();
 (DIR) diff --git a/dmenu_path b/dmenu_path
       t@@ -19,7 +19,7 @@ then
                        do
                                test -x "$file" && echo "$file"
                        done
       -        done | sort | uniq > "$CACHE".$$ &&
       +        done | sort -u > "$CACHE".$$ &&
                mv "$CACHE".$$ "$CACHE"
        fi