X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=dmenu.c;h=8b40aa7f1b4acca519aed10c7f8dca246eb3a7c0;hb=2ec16d9cb2661c834e346b4cdef29449ddc2f29c;hp=15ce8c75e463e74be1fae896905cc314f8b06289;hpb=9a33a72c6afd9042c8395f4318bf5d21e235694d;p=dmenu.git diff --git a/dmenu.c b/dmenu.c index 15ce8c7..8b40aa7 100644 --- a/dmenu.c +++ b/dmenu.c @@ -21,25 +21,6 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define IS_UTF8_1ST_CHAR(c) ((((c) & 0xc0) == 0xc0) || !((c) & 0x80)) -/* enums */ -enum { ColFG, ColBG, ColLast }; - -/* typedefs */ -typedef struct { - int x, y, w, h; - unsigned long norm[ColLast]; - unsigned long sel[ColLast]; - Drawable drawable; - GC gc; - struct { - XFontStruct *xfont; - XFontSet set; - int ascent; - int descent; - int height; - } font; -} DC; /* draw context */ - typedef struct Item Item; struct Item { char *text; @@ -53,24 +34,18 @@ static void calcoffsetsh(void); static void calcoffsetsv(void); static char *cistrstr(const char *s, const char *sub); static void cleanup(void); -static void drawcursor(void); static void drawmenu(void); static void drawmenuh(void); static void drawmenuv(void); -static void drawtext(const char *text, unsigned long col[ColLast]); -static void eprint(const char *errstr, ...); -static unsigned long getcolor(const char *colstr); static Bool grabkeyboard(void); -static void initfont(const char *fontstr); static void kpress(XKeyEvent * e); static void match(char *pattern); static void readstdin(void); static void run(void); static void setup(Bool topbar); -static int textnw(const char *text, unsigned int len); -static int textw(const char *text); #include "config.h" +#include "draw.h" /* variables */ static char *maxname = NULL; @@ -79,25 +54,26 @@ static char text[4096]; static int cmdw = 0; static int promptw = 0; static int ret = 0; -static int screen; -static unsigned int mw, mh; -static unsigned int cursor = 0; +static unsigned int lines = 0; static unsigned int numlockmask = 0; static Bool running = True; -static Display *dpy; -static DC dc; 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 parent, win; +static Window win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; -static unsigned int lines = 0; static void (*calcoffsets)(void) = calcoffsetsh; +Display *dpy; +DC dc; +int screen; +unsigned int mw, mh; +Window parent; + void appenditem(Item *i, Item **list, Item **last) { if(!(*last)) @@ -161,26 +137,19 @@ cistrstr(const char *s, const char *sub) { void cleanup(void) { - if(dc.font.set) - XFreeFontSet(dpy, dc.font.set); - else - XFreeFont(dpy, dc.font.xfont); - XFreePixmap(dpy, dc.drawable); - XFreeGC(dpy, dc.gc); + Item *itm; + + while(allitems) { + itm = allitems->next; + free(allitems->text); + free(allitems); + allitems = itm; + } + drawcleanup(); XDestroyWindow(dpy, win); XUngrabKeyboard(dpy, CurrentTime); } -void -drawcursor(void) { - XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 }; - - r.x += textnw(text, cursor) + dc.font.height / 2; - - XSetForeground(dpy, dc.gc, dc.norm[ColFG]); - XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); -} - void drawmenu(void) { dc.x = 0; @@ -199,7 +168,6 @@ drawmenu(void) { if(cmdw && item && lines == 0) dc.w = cmdw; drawtext(*text ? text : NULL, dc.norm); - drawcursor(); if(curr) { if(lines > 0) drawmenuv(); @@ -243,54 +211,6 @@ drawmenuv(void) { drawtext(NULL, dc.norm); } -void -drawtext(const char *text, unsigned long col[ColLast]) { - char buf[256]; - int i, x, y, h, 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; - olen = strlen(text); - h = dc.font.height; - y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent; - x = dc.x + (h / 2); - /* shorten text if necessary */ - for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--); - if(!len) - return; - memcpy(buf, text, len); - if(len < olen) - for(i = len; i && i > len - 3; buf[--i] = '.'); - 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 -eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -unsigned long -getcolor(const char *colstr) { - Colormap cmap = DefaultColormap(dpy, screen); - XColor color; - - if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) - eprint("dmenu: cannot allocate color '%s'\n", colstr); - return color.pixel; -} - Bool grabkeyboard(void) { unsigned int len; @@ -304,37 +224,6 @@ grabkeyboard(void) { return len > 0; } -void -initfont(const char *fontstr) { - char *def, **missing = NULL; - int i, n; - - if(!fontstr || fontstr[0] == '\0') - eprint("dmenu: cannot load font: '%s'\n", fontstr); - dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); - if(missing) - XFreeStringList(missing); - if(dc.font.set) { - XFontStruct **xfonts; - char **font_names; - dc.font.ascent = dc.font.descent = 0; - n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); - for(i = 0; i < n; i++) { - dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); - dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent); - xfonts++; - } - } - else { - if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) - && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) - eprint("dmenu: cannot load font: '%s'\n", fontstr); - dc.font.ascent = dc.font.xfont->ascent; - dc.font.descent = dc.font.xfont->descent; - } - dc.font.height = dc.font.ascent + dc.font.descent; -} - void kpress(XKeyEvent * e) { char buf[sizeof text]; @@ -381,9 +270,6 @@ kpress(XKeyEvent * e) { case XK_j: ksym = XK_Return; break; - case XK_k: - text[cursor] = '\0'; - break; case XK_n: ksym = XK_Down; break; @@ -391,67 +277,42 @@ kpress(XKeyEvent * e) { ksym = XK_Up; break; case XK_u: - memmove(text, text + cursor, sizeof text - cursor + 1); - cursor = 0; + text[0] = '\0'; match(text); break; case XK_w: - if(cursor > 0) { - i = cursor; - while(i-- > 0 && text[i] == ' '); - while(i-- > 0 && text[i] != ' '); - memmove(text + i + 1, text + cursor, sizeof text - cursor + 1); - cursor = i + 1; - match(text); - } + if(len == 0) + return; + i = len; + while(i-- > 0 && text[i] == ' '); + while(i-- > 0 && text[i] != ' '); + text[++i] = '\0'; + match(text); break; - case XK_y: - { - FILE *fp; - char *s; - if(!(fp = popen("sselp", "r"))) - eprint("dmenu: cannot popen sselp\n"); - s = fgets(buf, sizeof buf, fp); - pclose(fp); - if(s == NULL) - return; - } - num = strlen(buf); - if(num && buf[num-1] == '\n') - buf[--num] = '\0'; + case XK_x: + execlp("dinput", "dinput", text, NULL); /* todo: argv */ + eprint("dmenu: cannot exec dinput:"); break; } } switch(ksym) { default: - num = MIN(num, sizeof text - cursor); + num = MIN(num, sizeof text); if(num && !iscntrl((int) buf[0])) { - memmove(text + cursor + num, text + cursor, sizeof text - cursor - num); - memcpy(text + cursor, buf, num); - cursor += num; + memcpy(text + len, buf, num + 1); + len += num; match(text); } break; case XK_BackSpace: - if(cursor == 0) + if(len == 0) return; - for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++); - memmove(text + cursor - i, text + cursor, sizeof text - cursor + i); - cursor -= i; - match(text); - break; - case XK_Delete: - if(cursor == len) - return; - for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++); - memmove(text + cursor, text + cursor + i, sizeof text - cursor); + for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++); + len -= i; + text[len] = '\0'; match(text); break; case XK_End: - if(cursor < len) { - cursor = len; - break; - } while(next) { sel = curr = next; calcoffsets(); @@ -464,20 +325,10 @@ kpress(XKeyEvent * e) { running = False; return; case XK_Home: - if(sel == item) { - cursor = 0; - break; - } sel = curr = item; calcoffsets(); break; case XK_Left: - if(cursor > 0 && (!sel || !sel->left)) { - while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor])); - break; - } - if(lines > 0) - return; case XK_Up: if(!sel || !sel->left) return; @@ -508,12 +359,6 @@ kpress(XKeyEvent * e) { running = False; return; case XK_Right: - if(cursor < len) { - while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor])); - break; - } - if(lines > 0) - return; case XK_Down: if(!sel || !sel->right) return; @@ -527,7 +372,6 @@ kpress(XKeyEvent * e) { if(!sel) return; strncpy(text, sel->text, sizeof text); - cursor = strlen(text); match(text); break; } @@ -644,11 +488,6 @@ setup(Bool topbar) { } XFreeModifiermap(modmap); - /* style */ - dc.norm[ColBG] = getcolor(normbgcolor); - dc.norm[ColFG] = getcolor(normfgcolor); - dc.sel[ColBG] = getcolor(selbgcolor); - dc.sel[ColFG] = getcolor(selfgcolor); initfont(font); /* menu window */ @@ -689,12 +528,7 @@ setup(Bool topbar) { DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - /* pixmap */ - dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, parent, 0, NULL); - XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); - if(!dc.font.set) - XSetFont(dpy, dc.gc, dc.font.xfont->fid); + drawsetup(); if(maxname) cmdw = MIN(textw(maxname), mw / 3); if(prompt) @@ -704,22 +538,6 @@ setup(Bool topbar) { XMapRaised(dpy, win); } -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); -} - -int -textw(const char *text) { - return textnw(text, strlen(text)) + dc.font.height; -} - int main(int argc, char *argv[]) { unsigned int i;