Browse Source

reorganized

master
Anselm R. Garbe 17 years ago
parent
commit
d094ebea96
  1. 583
      dmenu.c

583
dmenu.c

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

Loading…
Cancel
Save