diff options
Diffstat (limited to 'dmenu.c')
-rw-r--r-- | dmenu.c | 222 |
1 files changed, 94 insertions, 128 deletions
@@ -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> @@ -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)) @@ -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; @@ -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; @@ -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; } @@ -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 @@ -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); } @@ -254,6 +227,7 @@ keypress(XKeyEvent *e) { break; case XK_k: /* delete right */ text[cursor] = '\0'; + match(); break; case XK_n: ksym = XK_Down; @@ -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; } @@ -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: @@ -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(); @@ -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; } } @@ -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) @@ -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; @@ -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); } @@ -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); @@ -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")) @@ -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(); |