aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dmenu.c587
1 files changed, 299 insertions, 288 deletions
diff --git a/dmenu.c b/dmenu.c
index b684175..34df9ed 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -40,134 +40,55 @@ struct Item {
};
/* forward declarations */
-static void *emalloc(unsigned int size);
-static void eprint(const char *errstr, ...);
-static char *estrdup(const char *str);
-static void drawtext(const char *text, unsigned long col[ColLast]);
-static unsigned int textw(const char *text);
-static unsigned int textnw(const char *text, unsigned int len);
-static void calcoffsets(void);
-static void drawmenu(void);
-static Bool grabkeyboard(void);
-static unsigned long getcolor(const char *colstr);
-static void initfont(const char *fontstr);
-static int strido(const char *text, const char *pattern);
-static void match(char *pattern);
-static void kpress(XKeyEvent * e);
-static char *readstdin(void);
-static void usage(void);
-
-
-/* variables */
-static int screen;
-static Display *dpy;
-static DC dc = {0};
-static char text[4096];
-static char *prompt = NULL;
-static int mw, mh;
-static int ret = 0;
-static int nitem = 0;
-static unsigned int cmdw = 0;
-static unsigned int promptw = 0;
-static unsigned int numlockmask = 0;
-static Bool running = True;
-static Item *allitems = NULL; /* first of all items */
-static Item *item = NULL; /* first of pattern matching items */
-static Item *sel = NULL;
-static Item *next = NULL;
-static Item *prev = NULL;
-static Item *curr = NULL;
-static Window root;
-static Window win;
+void calcoffsets(void);
+void cleanup(void);
+void drawmenu(void);
+void drawtext(const char *text, unsigned long col[ColLast]);
+void *emalloc(unsigned int size);
+void eprint(const char *errstr, ...);
+char *estrdup(const char *str);
+unsigned long getcolor(const char *colstr);
+Bool grabkeyboard(void);
+void initfont(const char *fontstr);
+void kpress(XKeyEvent * e);
+void match(char *pattern);
+void readstdin(void);
+void run(void);
+void setup(Bool bottom);
+int strido(const char *text, const char *pattern);
+unsigned int textnw(const char *text, unsigned int len);
+unsigned int textw(const char *text);
#include "config.h"
-static void *
-emalloc(unsigned int size) {
- void *res = malloc(size);
-
- if(!res)
- eprint("fatal: could not malloc() %u bytes\n", size);
- return res;
-}
-
-static void
-eprint(const char *errstr, ...) {
- va_list ap;
-
- va_start(ap, errstr);
- vfprintf(stderr, errstr, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
-}
-
-static char *
-estrdup(const char *str) {
- void *res = strdup(str);
-
- if(!res)
- eprint("fatal: could not malloc() %u bytes\n", strlen(str));
- return res;
-}
-
-
-static void
-drawtext(const char *text, unsigned long col[ColLast]) {
- int x, y, w, h;
- static char buf[256];
- unsigned int len, olen;
- XRectangle r = { dc.x, dc.y, dc.w, dc.h };
-
- XSetForeground(dpy, dc.gc, col[ColBG]);
- XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
- if(!text)
- return;
- w = 0;
- olen = len = strlen(text);
- if(len >= sizeof buf)
- 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;
- x = dc.x + (h / 2);
- /* shorten text if necessary */
- while(len && (w = textnw(buf, len)) > dc.w - h)
- buf[--len] = 0;
- if(len < olen) {
- if(len > 1)
- buf[len - 1] = '.';
- if(len > 2)
- buf[len - 2] = '.';
- if(len > 3)
- buf[len - 3] = '.';
- }
- if(w > dc.w)
- return; /* too long */
- XSetForeground(dpy, dc.gc, col[ColFG]);
- if(dc.font.set)
- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
- else
- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
-}
-
-static unsigned int
-textw(const char *text) {
- return textnw(text, strlen(text)) + dc.font.height;
-}
-
-static unsigned int
-textnw(const char *text, unsigned int len) {
- XRectangle r;
-
- if(dc.font.set) {
- XmbTextExtents(dc.font.set, text, len, NULL, &r);
- return r.width;
- }
- return XTextWidth(dc.font.xfont, text, len);
-}
-
-static void
+/* variables */
+char *font = FONT;
+char *maxname = NULL;
+char *normbg = NORMBGCOLOR;
+char *normfg = NORMFGCOLOR;
+char *prompt = NULL;
+char *selbg = SELBGCOLOR;
+char *selfg = SELFGCOLOR;
+char text[4096];
+int screen;
+int ret = 0;
+unsigned int cmdw = 0;
+unsigned int mw, mh;
+unsigned int promptw = 0;
+unsigned int nitem = 0;
+unsigned int numlockmask = 0;
+Bool running = True;
+Display *dpy;
+DC dc = {0};
+Item *allitems = NULL; /* first of all items */
+Item *item = NULL; /* first of pattern matching items */
+Item *sel = NULL;
+Item *next = NULL;
+Item *prev = NULL;
+Item *curr = NULL;
+Window root, win;
+
+void
calcoffsets(void) {
unsigned int tw, w;
@@ -193,7 +114,27 @@ calcoffsets(void) {
}
}
-static void
+void
+cleanup(void) {
+ Item *itm;
+
+ while(allitems) {
+ itm = allitems->next;
+ free(allitems->text);
+ free(allitems);
+ allitems = itm;
+ }
+ if(dc.font.set)
+ XFreeFontSet(dpy, dc.font.set);
+ else
+ XFreeFont(dpy, dc.font.xfont);
+ XFreePixmap(dpy, dc.drawable);
+ XFreeGC(dpy, dc.gc);
+ XDestroyWindow(dpy, win);
+ XUngrabKeyboard(dpy, CurrentTime);
+}
+
+void
drawmenu(void) {
Item *i;
@@ -234,20 +175,75 @@ drawmenu(void) {
XFlush(dpy);
}
-static Bool
-grabkeyboard(void) {
- unsigned int len;
+void
+drawtext(const char *text, unsigned long col[ColLast]) {
+ int x, y, w, h;
+ static char buf[256];
+ unsigned int len, olen;
+ XRectangle r = { dc.x, dc.y, dc.w, dc.h };
- for(len = 1000; len; len--) {
- if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
- == GrabSuccess)
- break;
- usleep(1000);
+ XSetForeground(dpy, dc.gc, col[ColBG]);
+ XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
+ if(!text)
+ return;
+ w = 0;
+ olen = len = strlen(text);
+ if(len >= sizeof buf)
+ 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;
+ x = dc.x + (h / 2);
+ /* shorten text if necessary */
+ while(len && (w = textnw(buf, len)) > dc.w - h)
+ buf[--len] = 0;
+ if(len < olen) {
+ if(len > 1)
+ buf[len - 1] = '.';
+ if(len > 2)
+ buf[len - 2] = '.';
+ if(len > 3)
+ buf[len - 3] = '.';
}
- return len > 0;
+ if(w > dc.w)
+ return; /* too long */
+ XSetForeground(dpy, dc.gc, col[ColFG]);
+ if(dc.font.set)
+ XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
+ else
+ XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
+}
+
+void *
+emalloc(unsigned int size) {
+ void *res = malloc(size);
+
+ if(!res)
+ eprint("fatal: could not malloc() %u bytes\n", size);
+ return res;
+}
+
+void
+eprint(const char *errstr, ...) {
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+char *
+estrdup(const char *str) {
+ void *res = strdup(str);
+
+ if(!res)
+ eprint("fatal: could not malloc() %u bytes\n", strlen(str));
+ return res;
}
-static unsigned long
+unsigned long
getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
@@ -257,7 +253,20 @@ getcolor(const char *colstr) {
return color.pixel;
}
-static void
+Bool
+grabkeyboard(void) {
+ unsigned int len;
+
+ for(len = 1000; len; len--) {
+ if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
+ == GrabSuccess)
+ break;
+ usleep(1000);
+ }
+ return len > 0;
+}
+
+void
initfont(const char *fontstr) {
char *def, **missing;
int i, n;
@@ -299,65 +308,7 @@ initfont(const char *fontstr) {
dc.font.height = dc.font.ascent + dc.font.descent;
}
-static int
-strido(const char *text, const char *pattern) {
- for(; *text && *pattern; text++)
- if (*text == *pattern)
- pattern++;
- return !*pattern;
-}
-
-static void
-match(char *pattern) {
- unsigned int plen;
- Item *i, *j;
-
- if(!pattern)
- return;
- plen = strlen(pattern);
- item = j = NULL;
- nitem = 0;
- for(i = allitems; i; i=i->next)
- if(!plen || !strncmp(pattern, i->text, plen)) {
- if(!j)
- item = i;
- else
- j->right = i;
- i->left = j;
- i->right = NULL;
- j = i;
- nitem++;
- }
- for(i = allitems; i; i=i->next)
- if(plen && strncmp(pattern, i->text, plen)
- && strstr(i->text, pattern)) {
- if(!j)
- item = i;
- else
- j->right = i;
- i->left = j;
- i->right = NULL;
- j = i;
- nitem++;
- }
- for(i = allitems; i; i=i->next)
- if(plen && strncmp(pattern, i->text, plen)
- && !strstr(i->text, pattern)
- && strido(i->text,pattern)) {
- if(!j)
- item = i;
- else
- j->right = i;
- i->left = j;
- i->right = NULL;
- j = i;
- nitem++;
- }
- curr = prev = next = sel = item;
- calcoffsets();
-}
-
-static void
+void
kpress(XKeyEvent * e) {
char buf[32];
int i, num;
@@ -528,9 +479,58 @@ kpress(XKeyEvent * e) {
drawmenu();
}
-static char *
+void
+match(char *pattern) {
+ unsigned int plen;
+ Item *i, *j;
+
+ if(!pattern)
+ return;
+ plen = strlen(pattern);
+ item = j = NULL;
+ nitem = 0;
+ for(i = allitems; i; i=i->next)
+ if(!plen || !strncmp(pattern, i->text, plen)) {
+ if(!j)
+ item = i;
+ else
+ j->right = i;
+ i->left = j;
+ i->right = NULL;
+ j = i;
+ nitem++;
+ }
+ for(i = allitems; i; i=i->next)
+ if(plen && strncmp(pattern, i->text, plen)
+ && strstr(i->text, pattern)) {
+ if(!j)
+ item = i;
+ else
+ j->right = i;
+ i->left = j;
+ i->right = NULL;
+ j = i;
+ nitem++;
+ }
+ for(i = allitems; i; i=i->next)
+ if(plen && strncmp(pattern, i->text, plen)
+ && !strstr(i->text, pattern)
+ && strido(i->text,pattern)) {
+ if(!j)
+ item = i;
+ else
+ j->right = i;
+ i->left = j;
+ i->right = NULL;
+ j = i;
+ nitem++;
+ }
+ curr = prev = next = sel = item;
+ calcoffsets();
+}
+
+void
readstdin(void) {
- static char *maxname = NULL;
char *p, buf[1024];
unsigned int len = 0, max = 0;
Item *i, *new;
@@ -554,88 +554,50 @@ readstdin(void) {
i->next = new;
i = new;
}
-
- return maxname;
}
-static void
-usage(void) {
- eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
- " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
+void
+run(void) {
+ XEvent ev;
+
+ /* main event loop */
+ while(running && !XNextEvent(dpy, &ev))
+ switch (ev.type) {
+ default: /* ignore all crap */
+ break;
+ case KeyPress:
+ kpress(&ev.xkey);
+ break;
+ case Expose:
+ if(ev.xexpose.count == 0)
+ drawmenu();
+ break;
+ }
}
-int
-main(int argc, char *argv[]) {
- Bool bottom = False;
- char *font = FONT;
- char *maxname;
- char *normbg = NORMBGCOLOR;
- char *normfg = NORMFGCOLOR;
- char *selbg = SELBGCOLOR;
- char *selfg = SELFGCOLOR;
- int i, j;
- Item *itm;
- XEvent ev;
+void
+setup(Bool bottom) {
+ unsigned int i, j;
XModifierKeymap *modmap;
XSetWindowAttributes wa;
- /* command line args */
- for(i = 1; i < argc; i++)
- if(!strcmp(argv[i], "-b")) {
- bottom = True;
- }
- else if(!strcmp(argv[i], "-fn")) {
- if(++i < argc) font = argv[i];
- }
- else if(!strcmp(argv[i], "-nb")) {
- if(++i < argc) normbg = argv[i];
- }
- else if(!strcmp(argv[i], "-nf")) {
- if(++i < argc) normfg = argv[i];
- }
- else if(!strcmp(argv[i], "-p")) {
- if(++i < argc) prompt = argv[i];
- }
- else if(!strcmp(argv[i], "-sb")) {
- if(++i < argc) selbg = argv[i];
- }
- else if(!strcmp(argv[i], "-sf")) {
- if(++i < argc) selfg = argv[i];
- }
- else if(!strcmp(argv[i], "-v"))
- eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n");
- else
- usage();
- setlocale(LC_CTYPE, "");
- dpy = XOpenDisplay(0);
- if(!dpy)
- eprint("dmenu: cannot open display\n");
- screen = DefaultScreen(dpy);
- root = RootWindow(dpy, screen);
- if(isatty(STDIN_FILENO)) {
- maxname = readstdin();
- running = grabkeyboard();
- }
- else { /* prevent keypress loss */
- running = grabkeyboard();
- maxname = readstdin();
- }
/* init modifier map */
modmap = XGetModifierMapping(dpy);
- for (i = 0; i < 8; i++) {
- for (j = 0; j < modmap->max_keypermod; j++) {
+ for(i = 0; i < 8; i++)
+ for(j = 0; j < modmap->max_keypermod; j++) {
if(modmap->modifiermap[i * modmap->max_keypermod + j]
== XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i);
}
- }
XFreeModifiermap(modmap);
+
/* style */
dc.norm[ColBG] = getcolor(normbg);
dc.norm[ColFG] = getcolor(normfg);
dc.sel[ColBG] = getcolor(selbg);
dc.sel[ColFG] = getcolor(selfg);
initfont(font);
+
/* menu window */
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
@@ -647,6 +609,7 @@ main(int argc, char *argv[]) {
DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
+
/* pixmap */
dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
@@ -664,38 +627,86 @@ main(int argc, char *argv[]) {
text[0] = 0;
match(text);
XMapRaised(dpy, win);
- drawmenu();
- XSync(dpy, False);
+}
- /* main event loop */
- while(running && !XNextEvent(dpy, &ev))
- switch (ev.type) {
- default: /* ignore all crap */
- break;
- case KeyPress:
- kpress(&ev.xkey);
- break;
- case Expose:
- if(ev.xexpose.count == 0)
- drawmenu();
- break;
+int
+strido(const char *text, const char *pattern) {
+ for(; *text && *pattern; text++)
+ if (*text == *pattern)
+ pattern++;
+ return !*pattern;
+}
+
+unsigned int
+textnw(const char *text, unsigned int len) {
+ XRectangle r;
+
+ if(dc.font.set) {
+ XmbTextExtents(dc.font.set, text, len, NULL, &r);
+ return r.width;
+ }
+ return XTextWidth(dc.font.xfont, text, len);
+}
+
+unsigned int
+textw(const char *text) {
+ return textnw(text, strlen(text)) + dc.font.height;
+}
+
+int
+main(int argc, char *argv[]) {
+ Bool bottom = False;
+ unsigned int i;
+
+ /* command line args */
+ for(i = 1; i < argc; i++)
+ if(!strcmp(argv[i], "-b")) {
+ bottom = True;
+ }
+ else if(!strcmp(argv[i], "-fn")) {
+ if(++i < argc) font = argv[i];
+ }
+ else if(!strcmp(argv[i], "-nb")) {
+ if(++i < argc) normbg = argv[i];
+ }
+ else if(!strcmp(argv[i], "-nf")) {
+ if(++i < argc) normfg = argv[i];
+ }
+ else if(!strcmp(argv[i], "-p")) {
+ if(++i < argc) prompt = argv[i];
+ }
+ else if(!strcmp(argv[i], "-sb")) {
+ if(++i < argc) selbg = argv[i];
+ }
+ else if(!strcmp(argv[i], "-sf")) {
+ if(++i < argc) selfg = argv[i];
}
+ else if(!strcmp(argv[i], "-v"))
+ eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n");
+ else
+ eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
+ " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
+ setlocale(LC_CTYPE, "");
+ dpy = XOpenDisplay(0);
+ if(!dpy)
+ eprint("dmenu: cannot open display\n");
+ screen = DefaultScreen(dpy);
+ root = RootWindow(dpy, screen);
- /* cleanup */
- while(allitems) {
- itm = allitems->next;
- free(allitems->text);
- free(allitems);
- allitems = itm;
+ if(isatty(STDIN_FILENO)) {
+ readstdin();
+ running = grabkeyboard();
}
- if(dc.font.set)
- XFreeFontSet(dpy, dc.font.set);
- else
- XFreeFont(dpy, dc.font.xfont);
- XFreePixmap(dpy, dc.drawable);
- XFreeGC(dpy, dc.gc);
- XDestroyWindow(dpy, win);
- XUngrabKeyboard(dpy, CurrentTime);
+ else { /* prevent keypress loss */
+ running = grabkeyboard();
+ readstdin();
+ }
+
+ setup(bottom);
+ drawmenu();
+ XSync(dpy, False);
+ run();
+ cleanup();
XCloseDisplay(dpy);
return ret;
}