dmenu

dynamic menu
git clone git://git.suckless.org/dmenu
Log | Files | Refs | README | LICENSE

commit 855a56631916bdff1438e11c232b88450f973648
parent 29e8faed6cf4b296382439651cf04596d276f080
Author: Connor Lane Smith <cls@lubutu.com>
Date:   Fri,  2 Jul 2010 06:49:05 +0100

added dmenu.h, common.c
Diffstat:
MMakefile | 10+++++++---
Acommon.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfig.def.h | 11+++++------
Mdinput.c | 150+++++--------------------------------------------------------------------------
Mdmenu.c | 188+++++++++++--------------------------------------------------------------------
Admenu.h | 30++++++++++++++++++++++++++++++
6 files changed, 204 insertions(+), 314 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = dinput.c dmenu.c +SRC = dinput.c dmenu.c common.c OBJ = ${SRC:.c=.o} all: options dinput dmenu @@ -24,9 +24,13 @@ config.h: @echo creating $@ from config.def.h @cp config.def.h $@ -.o: +dinput: dinput.o common.o @echo CC -o $@ - @${CC} -o $@ $< ${LDFLAGS} + @${CC} -o $@ $+ ${LDFLAGS} + +dmenu: dmenu.o common.o + @echo CC -o $@ + @${CC} -o $@ $+ ${LDFLAGS} clean: @echo cleaning diff --git a/common.c b/common.c @@ -0,0 +1,129 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <X11/keysym.h> +#ifdef XINERAMA +#include <X11/extensions/Xinerama.h> +#endif +#include "dmenu.h" + +/* variables */ +char *prompt = NULL; +char text[4096] = ""; +int promptw = 0; +int screen; +unsigned int numlockmask = 0; +unsigned int mw, mh; +unsigned long normcol[ColLast]; +unsigned long selcol[ColLast]; +Bool topbar = True; +DC dc; +Display *dpy; +Window win, root; + +void +grabkeyboard(void) { + unsigned int len; + + for(len = 1000; len; len--) { + if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) + == GrabSuccess) + return; + usleep(1000); + } + exit(EXIT_FAILURE); +} + +void +run(void) { + XEvent ev; + + /* main event loop */ + XSync(dpy, False); + while(!XNextEvent(dpy, &ev)) + switch(ev.type) { + case KeyPress: + kpress(&ev.xkey); + break; + case Expose: + if(ev.xexpose.count == 0) + drawbar(); + break; + case VisibilityNotify: + if(ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; + } + exit(EXIT_FAILURE); +} + +void +setup(unsigned int lines) { + int i, j, x, y; +#if XINERAMA + int n; + XineramaScreenInfo *info = NULL; +#endif + XModifierKeymap *modmap; + XSetWindowAttributes wa; + + /* init modifier map */ + modmap = XGetModifierMapping(dpy); + 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); + + dc.dpy = dpy; + normcol[ColBG] = getcolor(&dc, normbgcolor); + normcol[ColFG] = getcolor(&dc, normfgcolor); + selcol[ColBG] = getcolor(&dc, selbgcolor); + selcol[ColFG] = getcolor(&dc, selfgcolor); + initfont(&dc, font); + + /* input window */ + wa.override_redirect = True; + wa.background_pixmap = ParentRelative; + wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + + /* input window geometry */ + mh = (dc.font.height + 2) * (lines + 1); +#if XINERAMA + if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { + i = 0; + if(n > 1) { + int di; + unsigned int dui; + Window dummy; + if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) + 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; + } + x = info[i].x_org; + y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh; + mw = info[i].width; + XFree(info); + } + else +#endif + { + x = 0; + y = topbar ? 0 : DisplayHeight(dpy, screen) - mh; + mw = DisplayWidth(dpy, screen); + } + + win = XCreateWindow(dpy, root, x, y, mw, mh, 0, + DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + + setupdraw(&dc, win); + if(prompt) + promptw = MIN(textw(&dc, prompt), mw / 5); + XMapRaised(dpy, win); +} diff --git a/config.def.h b/config.def.h @@ -1,9 +1,8 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ -const char *font = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*"; -const char *normbgcolor = "#cccccc"; -const char *normfgcolor = "#000000"; -const char *selbgcolor = "#0066ff"; -const char *selfgcolor = "#ffffff"; -unsigned int spaceitem = 30; /* px between menu items */ +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"; diff --git a/dinput.c b/dinput.c @@ -4,45 +4,16 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> #include <X11/keysym.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#ifdef XINERAMA -#include <X11/extensions/Xinerama.h> -#endif -#include <draw.h> - -/* macros */ -#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)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define IS_UTF8_1ST_CHAR(c) ((((c) & 0xc0) == 0xc0) || !((c) & 0x80)) +#include "dmenu.h" /* forward declarations */ static void cleanup(void); -static void drawinput(void); -static void grabkeyboard(void); -static void kpress(XKeyEvent *e); -static void run(void); -static void setup(void); - -#include "config.h" /* variables */ -static char *prompt = NULL; -static char text[4096]; -static int promptw = 0; -static int screen; static size_t cursor = 0; -static unsigned int numlockmask = 0; -static unsigned int mw, mh; -static unsigned long normcol[ColLast]; -static unsigned long selcol[ColLast]; -static Bool topbar = True; -static DC dc; -static Display *dpy; -static Window win, root; void cleanup(void) { @@ -53,7 +24,7 @@ cleanup(void) { } void -drawinput(void) +drawbar(void) { dc.x = 0; dc.y = 0; @@ -73,19 +44,6 @@ drawinput(void) } void -grabkeyboard(void) { - unsigned int len; - - for(len = 1000; len; len--) { - if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) - == GrabSuccess) - return; - usleep(1000); - } - exit(EXIT_FAILURE); -} - -void kpress(XKeyEvent *e) { char buf[sizeof text]; int num; @@ -207,101 +165,7 @@ kpress(XKeyEvent *e) { while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor])); break; } - drawinput(); -} - -void -run(void) { - XEvent ev; - - /* main event loop */ - XSync(dpy, False); - while(!XNextEvent(dpy, &ev)) - switch(ev.type) { - case KeyPress: - kpress(&ev.xkey); - break; - case Expose: - if(ev.xexpose.count == 0) - drawinput(); - break; - case VisibilityNotify: - if(ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dpy, win); - break; - } - exit(EXIT_FAILURE); -} - -void -setup(void) { - int i, j, x, y; -#if XINERAMA - int n; - XineramaScreenInfo *info = NULL; -#endif - XModifierKeymap *modmap; - XSetWindowAttributes wa; - - /* init modifier map */ - modmap = XGetModifierMapping(dpy); - 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); - - dc.dpy = dpy; - normcol[ColBG] = getcolor(&dc, normbgcolor); - normcol[ColFG] = getcolor(&dc, normfgcolor); - selcol[ColBG] = getcolor(&dc, selbgcolor); - selcol[ColFG] = getcolor(&dc, selfgcolor); - initfont(&dc, font); - - /* input window */ - wa.override_redirect = True; - wa.background_pixmap = ParentRelative; - wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - - /* input window geometry */ - mh = dc.font.height + 2; -#if XINERAMA - if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { - i = 0; - if(n > 1) { - int di; - unsigned int dui; - Window dummy; - if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) - 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; - } - x = info[i].x_org; - y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh; - mw = info[i].width; - XFree(info); - } - else -#endif - { - x = 0; - y = topbar ? 0 : DisplayHeight(dpy, screen) - mh; - mw = DisplayWidth(dpy, screen); - } - - win = XCreateWindow(dpy, root, x, y, mw, mh, 0, - DefaultDepth(dpy, screen), CopyFromParent, - DefaultVisual(dpy, screen), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - - setupdraw(&dc, win); - if(prompt) - promptw = MIN(textw(&dc, prompt), mw / 5); - cursor = strlen(text); - XMapRaised(dpy, win); + drawbar(); } int @@ -336,11 +200,13 @@ main(int argc, char *argv[]) { if(++i < argc) selfgcolor = argv[i]; } else if(!strcmp(argv[i], "-v")) { - printf("dinput-"VERSION", © 2006-2010 dinput engineers, see LICENSE for details\n"); + printf("dinput-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n"); exit(EXIT_SUCCESS); } - else if(!*text) + else if(!*text) { strncpy(text, argv[i], sizeof text); + cursor = strlen(text); + } else { fputs("usage: dinput [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n" " [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n", stderr); @@ -356,7 +222,7 @@ main(int argc, char *argv[]) { root = RootWindow(dpy, screen); grabkeyboard(); - setup(); + setup(0); run(); return 0; } diff --git a/dmenu.c b/dmenu.c @@ -8,16 +8,7 @@ #include <X11/keysym.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#ifdef XINERAMA -#include <X11/extensions/Xinerama.h> -#endif -#include <draw.h> - -/* macros */ -#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)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define IS_UTF8_1ST_CHAR(c) ((((c) & 0xc0) == 0xc0) || !((c) & 0x80)) +#include "dmenu.h" typedef struct Item Item; struct Item { @@ -33,41 +24,22 @@ static void calcoffsetsv(void); static char *cistrstr(const char *s, const char *sub); static void cleanup(void); static void dinput(void); -static void drawmenu(void); static void drawmenuh(void); static void drawmenuv(void); -static void grabkeyboard(void); -static void kpress(XKeyEvent *e); -static void match(char *pattern); +static void match(void); static void readstdin(void); -static void run(void); -static void setup(void); - -#include "config.h" /* variables */ static char **argp = NULL; static char *maxname = NULL; -static char *prompt = NULL; -static char text[4096]; -static int cmdw = 0; -static int promptw = 0; -static int screen; +static unsigned int cmdw = 0; static unsigned int lines = 0; -static unsigned int numlockmask = 0; -static unsigned int mw, mh; -static unsigned long normcol[ColLast]; -static unsigned long selcol[ColLast]; -static Bool topbar = True; -static DC dc; -static Display *dpy; 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 win, root; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; static void (*calcoffsets)(void) = calcoffsetsh; @@ -85,14 +57,13 @@ appenditem(Item *i, Item **list, Item **last) { void calcoffsetsh(void) { - unsigned int x; + unsigned int w, x; - x = promptw + cmdw + (2 * spaceitem); - for(next = curr; next; next = next->right) + w = promptw + cmdw + textw(&dc, "<") + textw(&dc, ">"); + for(x = w, next = curr; next; next = next->right) if((x += MIN(textw(&dc, next->text), mw / 3)) > mw) break; - x = promptw + cmdw + (2 * spaceitem); - for(prev = curr; prev && prev->left; prev = prev->left) + for(x = w, prev = curr; prev && prev->left; prev = prev->left) if((x += MIN(textw(&dc, prev->left->text), mw / 3)) > mw) break; } @@ -157,7 +128,7 @@ dinput(void) { } void -drawmenu(void) { +drawbar(void) { dc.x = 0; dc.y = 0; dc.w = mw; @@ -188,7 +159,7 @@ drawmenuh(void) { Item *i; dc.x += cmdw; - dc.w = spaceitem; + dc.w = textw(&dc, "<"); drawtext(&dc, curr->left ? "<" : NULL, normcol); dc.x += dc.w; for(i = curr; i != next; i = i->right) { @@ -196,7 +167,7 @@ drawmenuh(void) { drawtext(&dc, i->text, (sel == i) ? selcol : normcol); dc.x += dc.w; } - dc.w = spaceitem; + dc.w = textw(&dc, ">"); dc.x = mw - dc.w; drawtext(&dc, next ? ">" : NULL, normcol); } @@ -218,19 +189,6 @@ drawmenuv(void) { } void -grabkeyboard(void) { - unsigned int len; - - for(len = 1000; len; len--) { - if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) - == GrabSuccess) - return; - usleep(1000); - } - exit(EXIT_FAILURE); -} - -void kpress(XKeyEvent *e) { char buf[sizeof text]; int num; @@ -285,7 +243,7 @@ kpress(XKeyEvent *e) { break; case XK_u: text[0] = '\0'; - match(text); + match(); break; case XK_w: if(len == 0) @@ -294,7 +252,7 @@ kpress(XKeyEvent *e) { while(i-- > 0 && text[i] == ' '); while(i-- > 0 && text[i] != ' '); text[++i] = '\0'; - match(text); + match(); break; } } @@ -304,7 +262,7 @@ kpress(XKeyEvent *e) { if(num && !iscntrl((int) buf[0])) { memcpy(text + len, buf, num + 1); len += num; - match(text); + match(); } break; case XK_BackSpace: @@ -313,7 +271,7 @@ kpress(XKeyEvent *e) { for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++); len -= i; text[len] = '\0'; - match(text); + match(); break; case XK_End: while(next) { @@ -373,24 +331,22 @@ kpress(XKeyEvent *e) { dinput(); break; } - drawmenu(); + drawbar(); } void -match(char *pattern) { - unsigned int plen; +match(void) { + unsigned int len; Item *i, *itemend, *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend; - if(!pattern) - return; - plen = strlen(pattern); + len = strlen(text); item = lexact = lprefix = lsubstr = itemend = exactend = prefixend = substrend = NULL; for(i = allitems; i; i = i->next) - if(!fstrncmp(pattern, i->text, plen + 1)) + if(!fstrncmp(text, i->text, len + 1)) appenditem(i, &lexact, &exactend); - else if(!fstrncmp(pattern, i->text, plen)) + else if(!fstrncmp(text, i->text, len)) appenditem(i, &lprefix, &prefixend); - else if(fstrstr(i->text, pattern)) + else if(fstrstr(i->text, text)) appenditem(i, &lsubstr, &substrend); if(lexact) { item = lexact; @@ -444,103 +400,6 @@ readstdin(void) { } } -void -run(void) { - XEvent ev; - - /* main event loop */ - XSync(dpy, False); - while(!XNextEvent(dpy, &ev)) - switch(ev.type) { - case KeyPress: - kpress(&ev.xkey); - break; - case Expose: - if(ev.xexpose.count == 0) - drawmenu(); - break; - case VisibilityNotify: - if(ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dpy, win); - break; - } - exit(EXIT_FAILURE); -} - -void -setup(void) { - int i, j, x, y; -#if XINERAMA - int n; - XineramaScreenInfo *info = NULL; -#endif - XModifierKeymap *modmap; - XSetWindowAttributes wa; - - /* init modifier map */ - modmap = XGetModifierMapping(dpy); - 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); - - dc.dpy = dpy; - normcol[ColBG] = getcolor(&dc, normbgcolor); - normcol[ColFG] = getcolor(&dc, normfgcolor); - selcol[ColBG] = getcolor(&dc, selbgcolor); - selcol[ColFG] = getcolor(&dc, selfgcolor); - initfont(&dc, font); - - /* menu window */ - wa.override_redirect = True; - wa.background_pixmap = ParentRelative; - wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - - /* menu window geometry */ - mh = (dc.font.height + 2) * (lines + 1); -#if XINERAMA - if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { - i = 0; - if(n > 1) { - int di; - unsigned int dui; - Window dummy; - if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) - 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; - } - x = info[i].x_org; - y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh; - mw = info[i].width; - XFree(info); - } - else -#endif - { - x = 0; - y = topbar ? 0 : mh - DisplayHeight(dpy, screen); - mw = DisplayWidth(dpy, screen); - } - - win = XCreateWindow(dpy, root, x, y, mw, mh, 0, - DefaultDepth(dpy, screen), CopyFromParent, - DefaultVisual(dpy, screen), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - - setupdraw(&dc, win); - if(maxname) - cmdw = MIN(textw(&dc, maxname), mw / 3); - if(prompt) - promptw = MIN(textw(&dc, prompt), mw / 5); - text[0] = '\0'; - match(text); - XMapRaised(dpy, win); -} - int main(int argc, char *argv[]) { unsigned int i; @@ -600,7 +459,10 @@ main(int argc, char *argv[]) { readstdin(); grabkeyboard(); - setup(); + setup(lines); + if(maxname) + cmdw = MIN(textw(&dc, maxname), mw / 3); + match(); run(); return 0; } diff --git a/dmenu.h b/dmenu.h @@ -0,0 +1,30 @@ +#include <X11/Xlib.h> +#include <draw.h> +#include "config.h" + +/* macros */ +#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)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define IS_UTF8_1ST_CHAR(c) ((((c) & 0xc0) == 0xc0) || !((c) & 0x80)) + +/* forward declarations */ +void drawbar(void); +void grabkeyboard(void); +void kpress(XKeyEvent *e); +void run(void); +void setup(unsigned int lines); + +/* variables */ +extern char *prompt; +extern char text[4096]; +extern int promptw; +extern int screen; +extern unsigned int numlockmask; +extern unsigned int mw, mh; +extern unsigned long normcol[ColLast]; +extern unsigned long selcol[ColLast]; +extern Bool topbar; +extern DC dc; +extern Display *dpy; +extern Window win, root;