merged dmenu & dinput (clunky interface)
This commit is contained in:
		
							parent
							
								
									7f36736d11
								
							
						
					
					
						commit
						7d5fe17391
					
				
					 5 changed files with 215 additions and 440 deletions
				
			
		
							
								
								
									
										15
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -3,7 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| include config.mk | include config.mk | ||||||
| 
 | 
 | ||||||
| SRC = dinput.c dmenu.c common.c | SRC = dmenu.c | ||||||
| OBJ = ${SRC:.c=.o} | OBJ = ${SRC:.c=.o} | ||||||
| 
 | 
 | ||||||
| all: options dinput dmenu | all: options dinput dmenu | ||||||
|  | @ -24,17 +24,13 @@ config.h: | ||||||
| 	@echo creating $@ from config.def.h | 	@echo creating $@ from config.def.h | ||||||
| 	@cp config.def.h $@ | 	@cp config.def.h $@ | ||||||
| 
 | 
 | ||||||
| dinput: dinput.o common.o | dmenu: ${OBJ} | ||||||
| 	@echo CC -o $@ |  | ||||||
| 	@${CC} -o $@ $+ ${LDFLAGS} |  | ||||||
| 
 |  | ||||||
| dmenu: dmenu.o common.o |  | ||||||
| 	@echo CC -o $@ | 	@echo CC -o $@ | ||||||
| 	@${CC} -o $@ $+ ${LDFLAGS} | 	@${CC} -o $@ $+ ${LDFLAGS} | ||||||
| 
 | 
 | ||||||
| clean: | clean: | ||||||
| 	@echo cleaning | 	@echo cleaning | ||||||
| 	@rm -f dinput dmenu ${OBJ} dmenu-${VERSION}.tar.gz | 	@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz | ||||||
| 
 | 
 | ||||||
| dist: clean | dist: clean | ||||||
| 	@echo creating dist tarball | 	@echo creating dist tarball | ||||||
|  | @ -47,8 +43,7 @@ dist: clean | ||||||
| install: all | install: all | ||||||
| 	@echo installing executable file to ${DESTDIR}${PREFIX}/bin | 	@echo installing executable file to ${DESTDIR}${PREFIX}/bin | ||||||
| 	@mkdir -p ${DESTDIR}${PREFIX}/bin | 	@mkdir -p ${DESTDIR}${PREFIX}/bin | ||||||
| 	@cp -f dinput dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin | 	@cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin | ||||||
| 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dinput |  | ||||||
| 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu | 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu | ||||||
| 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path | 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path | ||||||
| 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run | 	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run | ||||||
|  | @ -60,7 +55,7 @@ install: all | ||||||
| uninstall: | uninstall: | ||||||
| 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin | 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin | ||||||
| 	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path | 	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path | ||||||
| 	@rm -f ${DESTDIR}${PREFIX}/bin/dinput ${DESTDIR}${PREFIX}/bin/dmenu_run | 	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run | ||||||
| 	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 | 	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 | ||||||
| 	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 | 	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										129
									
								
								common.c
									
										
									
									
									
								
							
							
						
						
									
										129
									
								
								common.c
									
										
									
									
									
								
							|  | @ -1,129 +0,0 @@ | ||||||
| /* 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); |  | ||||||
| } |  | ||||||
							
								
								
									
										230
									
								
								dinput.c
									
										
									
									
									
								
							
							
						
						
									
										230
									
								
								dinput.c
									
										
									
									
									
								
							|  | @ -1,230 +0,0 @@ | ||||||
| /* See LICENSE file for copyright and license details. */ |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <locale.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <X11/keysym.h> |  | ||||||
| #include <X11/Xlib.h> |  | ||||||
| #include <X11/Xutil.h> |  | ||||||
| #include "dmenu.h" |  | ||||||
| 
 |  | ||||||
| /* forward declarations */ |  | ||||||
| static void cleanup(void); |  | ||||||
| 
 |  | ||||||
| /* variables */ |  | ||||||
| static size_t cursor = 0; |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| cleanup(void) { |  | ||||||
| 	cleanupdraw(&dc); |  | ||||||
| 	XDestroyWindow(dpy, win); |  | ||||||
| 	XUngrabKeyboard(dpy, CurrentTime); |  | ||||||
| 	XCloseDisplay(dpy); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| drawbar(void) |  | ||||||
| { |  | ||||||
| 	dc.x = 0; |  | ||||||
| 	dc.y = 0; |  | ||||||
| 	dc.w = mw; |  | ||||||
| 	dc.h = mh; |  | ||||||
| 	drawbox(&dc, normcol); |  | ||||||
| 	/* print prompt? */ |  | ||||||
| 	if(prompt) { |  | ||||||
| 		dc.w = promptw; |  | ||||||
| 		drawbox(&dc, selcol); |  | ||||||
| 		drawtext(&dc, prompt, selcol); |  | ||||||
| 		dc.x += dc.w; |  | ||||||
| 	} |  | ||||||
| 	dc.w = mw - dc.x; |  | ||||||
| 	drawtext(&dc, text, normcol); |  | ||||||
| 	drawline(&dc, textnw(&dc, text, cursor) + dc.font.height/2, 2, 1, |  | ||||||
| 			dc.font.height-2, normcol); |  | ||||||
| 	commitdraw(&dc, win); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| kpress(XKeyEvent *e) { |  | ||||||
| 	char buf[sizeof text]; |  | ||||||
| 	int num; |  | ||||||
| 	unsigned int i, len; |  | ||||||
| 	KeySym ksym; |  | ||||||
| 
 |  | ||||||
| 	len = strlen(text); |  | ||||||
| 	num = XLookupString(e, buf, sizeof buf, &ksym, NULL); |  | ||||||
| 	if(ksym == XK_KP_Enter) |  | ||||||
| 		ksym = XK_Return; |  | ||||||
| 	else if(ksym >= XK_KP_0 && ksym <= XK_KP_9) |  | ||||||
| 		ksym = (ksym - XK_KP_0) + XK_0; |  | ||||||
| 	else if(IsFunctionKey(ksym) || IsKeypadKey(ksym) |  | ||||||
| 	|| IsMiscFunctionKey(ksym) || IsPFKey(ksym) |  | ||||||
| 	|| IsPrivateKeypadKey(ksym)) |  | ||||||
| 		return; |  | ||||||
| 	/* first check if a control mask is omitted */ |  | ||||||
| 	if(e->state & ControlMask) { |  | ||||||
| 		switch(tolower(ksym)) { |  | ||||||
| 		default: |  | ||||||
| 			return; |  | ||||||
| 		case XK_a: |  | ||||||
| 			ksym = XK_Home; |  | ||||||
| 			break; |  | ||||||
| 		case XK_b: |  | ||||||
| 			ksym = XK_Left; |  | ||||||
| 			break; |  | ||||||
| 		case XK_c: |  | ||||||
| 			ksym = XK_Escape; |  | ||||||
| 			break; |  | ||||||
| 		case XK_e: |  | ||||||
| 			ksym = XK_End; |  | ||||||
| 			break; |  | ||||||
| 		case XK_f: |  | ||||||
| 			ksym = XK_Right; |  | ||||||
| 			break; |  | ||||||
| 		case XK_h: |  | ||||||
| 			ksym = XK_BackSpace; |  | ||||||
| 			break; |  | ||||||
| 		case XK_j: |  | ||||||
| 		case XK_m: |  | ||||||
| 			ksym = XK_Return; |  | ||||||
| 			break; |  | ||||||
| 		case XK_k: |  | ||||||
| 			text[cursor] = '\0'; |  | ||||||
| 			break; |  | ||||||
| 		case XK_u: |  | ||||||
| 			memmove(text, text + cursor, sizeof text - cursor + 1); |  | ||||||
| 			cursor = 0; |  | ||||||
| 			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; |  | ||||||
| 			} |  | ||||||
| 			break; |  | ||||||
| 		case XK_y: |  | ||||||
| 			{ |  | ||||||
| 				FILE *fp; |  | ||||||
| 				char *s; |  | ||||||
| 				if(!(fp = popen("sselp", "r"))) |  | ||||||
| 					eprint("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'; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	switch(ksym) { |  | ||||||
| 	default: |  | ||||||
| 		num = MIN(num, sizeof text - cursor); |  | ||||||
| 		if(num && !iscntrl((int) buf[0])) { |  | ||||||
| 			memmove(text + cursor + num, text + cursor, sizeof text - cursor - num); |  | ||||||
| 			memcpy(text + cursor, buf, num); |  | ||||||
| 			cursor += num; |  | ||||||
| 		} |  | ||||||
| 		break; |  | ||||||
| 	case XK_BackSpace: |  | ||||||
| 		if(cursor == 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; |  | ||||||
| 		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); |  | ||||||
| 		break; |  | ||||||
| 	case XK_End: |  | ||||||
| 		cursor = len; |  | ||||||
| 		break; |  | ||||||
| 	case XK_Escape: |  | ||||||
| 		exit(EXIT_FAILURE); |  | ||||||
| 	case XK_Home: |  | ||||||
| 		cursor = 0; |  | ||||||
| 		break; |  | ||||||
| 	case XK_Left: |  | ||||||
| 		if(cursor == 0) |  | ||||||
| 			return; |  | ||||||
| 		while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor])); |  | ||||||
| 		break; |  | ||||||
| 	case XK_Return: |  | ||||||
| 		fprintf(stdout, "%s", text); |  | ||||||
| 		fflush(stdout); |  | ||||||
| 		exit(EXIT_SUCCESS); |  | ||||||
| 	case XK_Right: |  | ||||||
| 		if(cursor == len) |  | ||||||
| 			return; |  | ||||||
| 		while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor])); |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 	drawbar(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int |  | ||||||
| main(int argc, char *argv[]) { |  | ||||||
| 	unsigned int i; |  | ||||||
| 
 |  | ||||||
| 	/* command line args */ |  | ||||||
| 	progname = "dinput"; |  | ||||||
| 	for(i = 1; i < argc; i++) |  | ||||||
| 		if(!strcmp(argv[i], "-i")) |  | ||||||
| 			;  /* ignore flag */ |  | ||||||
| 		else if(!strcmp(argv[i], "-b")) |  | ||||||
| 			topbar = False; |  | ||||||
| 		else if(!strcmp(argv[i], "-l")) |  | ||||||
| 			i++;  /* ignore flag */ |  | ||||||
| 		else if(!strcmp(argv[i], "-fn")) { |  | ||||||
| 			if(++i < argc) font = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-nb")) { |  | ||||||
| 			if(++i < argc) normbgcolor = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-nf")) { |  | ||||||
| 			if(++i < argc) normfgcolor = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-p")) { |  | ||||||
| 			if(++i < argc) prompt = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-sb")) { |  | ||||||
| 			if(++i < argc) selbgcolor = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-sf")) { |  | ||||||
| 			if(++i < argc) selfgcolor = argv[i]; |  | ||||||
| 		} |  | ||||||
| 		else if(!strcmp(argv[i], "-v")) { |  | ||||||
| 			printf("dinput-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n"); |  | ||||||
| 			exit(EXIT_SUCCESS); |  | ||||||
| 		} |  | ||||||
| 		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); |  | ||||||
| 			exit(EXIT_FAILURE); |  | ||||||
| 		} |  | ||||||
| 	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |  | ||||||
| 		fprintf(stderr, "dinput: warning: no locale support\n"); |  | ||||||
| 	if(!(dpy = XOpenDisplay(NULL))) |  | ||||||
| 		eprint("cannot open display\n"); |  | ||||||
| 	if(atexit(&cleanup) != 0) |  | ||||||
| 		eprint("cannot register cleanup\n"); |  | ||||||
| 	screen = DefaultScreen(dpy); |  | ||||||
| 	root = RootWindow(dpy, screen); |  | ||||||
| 
 |  | ||||||
| 	grabkeyboard(); |  | ||||||
| 	setup(0); |  | ||||||
| 	run(); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
							
								
								
									
										251
									
								
								dmenu.c
									
										
									
									
									
								
							
							
						
						
									
										251
									
								
								dmenu.c
									
										
									
									
									
								
							|  | @ -8,7 +8,16 @@ | ||||||
| #include <X11/keysym.h> | #include <X11/keysym.h> | ||||||
| #include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||||
| #include <X11/Xutil.h> | #include <X11/Xutil.h> | ||||||
| #include "dmenu.h" | #ifdef XINERAMA | ||||||
|  | #include <X11/extensions/Xinerama.h> | ||||||
|  | #endif | ||||||
|  | #include <draw.h> | ||||||
|  | #include "config.h" | ||||||
|  | 
 | ||||||
|  | #define INRECT(x,y,rx,ry,rw,rh) ((rx) < (x) && (x) < (rx)+(rw) && (ry) < (y) && (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) == 0x00) | ||||||
| 
 | 
 | ||||||
| typedef struct Item Item; | typedef struct Item Item; | ||||||
| struct Item { | struct Item { | ||||||
|  | @ -17,30 +26,46 @@ struct Item { | ||||||
| 	Item *left, *right; /* traverses items matching current search pattern */ | 	Item *left, *right; /* traverses items matching current search pattern */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* forward declarations */ |  | ||||||
| static void appenditem(Item *i, Item **list, Item **last); | static void appenditem(Item *i, Item **list, Item **last); | ||||||
| static void calcoffsetsh(void); | static void calcoffsetsh(void); | ||||||
| static void calcoffsetsv(void); | static void calcoffsetsv(void); | ||||||
| static char *cistrstr(const char *s, const char *sub); | static char *cistrstr(const char *s, const char *sub); | ||||||
| static void cleanup(void); | static void cleanup(void); | ||||||
| static void dinput(void); |  | ||||||
| static void drawitem(const char *s, unsigned long col[ColLast]); | static void drawitem(const char *s, unsigned long col[ColLast]); | ||||||
|  | static void drawmenu(void); | ||||||
| static void drawmenuh(void); | static void drawmenuh(void); | ||||||
| static void drawmenuv(void); | static void drawmenuv(void); | ||||||
|  | static void grabkeyboard(void); | ||||||
|  | static void keypress(XKeyEvent *e); | ||||||
| static void match(void); | static void match(void); | ||||||
| static void readstdin(void); | static void readstdin(void); | ||||||
|  | static void run(void); | ||||||
|  | static void setup(void); | ||||||
| 
 | 
 | ||||||
| /* variables */ |  | ||||||
| static char **argp = NULL; | static char **argp = NULL; | ||||||
| static char *maxname = NULL; | static char *maxname = NULL; | ||||||
|  | static char *prompt; | ||||||
|  | static char text[4096]; | ||||||
|  | static int promptw; | ||||||
|  | static int screen; | ||||||
|  | static size_t cur = 0; | ||||||
| static unsigned int cmdw = 0; | static unsigned int cmdw = 0; | ||||||
| static unsigned int lines = 0; | static unsigned int lines = 0; | ||||||
|  | static unsigned int numlockmask; | ||||||
|  | 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 *allitems = NULL;  /* first of all items */ | ||||||
| static Item *item = NULL;      /* first of pattern matching items */ | static Item *item = NULL;      /* first of pattern matching items */ | ||||||
| static Item *sel = NULL; | static Item *sel = NULL; | ||||||
| static Item *next = NULL; | static Item *next = NULL; | ||||||
| static Item *prev = NULL; | static Item *prev = NULL; | ||||||
| static Item *curr = NULL; | static Item *curr = NULL; | ||||||
|  | static Window win, root; | ||||||
|  | 
 | ||||||
| static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; | ||||||
| static char *(*fstrstr)(const char *, const char *) = strstr; | static char *(*fstrstr)(const char *, const char *) = strstr; | ||||||
| static void (*calcoffsets)(void) = calcoffsetsh; | static void (*calcoffsets)(void) = calcoffsetsh; | ||||||
|  | @ -120,16 +145,18 @@ cleanup(void) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| dinput(void) { | drawitem(const char *s, unsigned long col[ColLast]) { | ||||||
| 	cleanup(); | 	const char *p; | ||||||
| 	argp[0] = "dinput"; | 	unsigned int w = textnw(&dc, text, strlen(text)); | ||||||
| 	argp[1] = text; | 
 | ||||||
| 	execvp("dinput", argp); | 	drawbox(&dc, col); | ||||||
| 	eprint("cannot exec dinput\n"); | 	drawtext(&dc, s, col); | ||||||
|  | 	for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++) | ||||||
|  | 		drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| drawbar(void) { | drawmenu(void) { | ||||||
| 	dc.x = 0; | 	dc.x = 0; | ||||||
| 	dc.y = 0; | 	dc.y = 0; | ||||||
| 	dc.w = mw; | 	dc.w = mw; | ||||||
|  | @ -149,6 +176,7 @@ drawbar(void) { | ||||||
| 	if(cmdw && item && lines == 0) | 	if(cmdw && item && lines == 0) | ||||||
| 		dc.w = cmdw; | 		dc.w = cmdw; | ||||||
| 	drawtext(&dc, text, normcol); | 	drawtext(&dc, text, normcol); | ||||||
|  | 	drawline(&dc, textnw(&dc, text, cur) + dc.h/2 - 2, 2, 1, dc.h-4, normcol); | ||||||
| 	if(lines > 0) | 	if(lines > 0) | ||||||
| 		drawmenuv(); | 		drawmenuv(); | ||||||
| 	else if(curr) | 	else if(curr) | ||||||
|  | @ -156,17 +184,6 @@ drawbar(void) { | ||||||
| 	commitdraw(&dc, win); | 	commitdraw(&dc, win); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void |  | ||||||
| drawitem(const char *s, unsigned long col[ColLast]) { |  | ||||||
| 	const char *p; |  | ||||||
| 	unsigned int w = textnw(&dc, text, strlen(text)); |  | ||||||
| 
 |  | ||||||
| 	drawbox(&dc, col); |  | ||||||
| 	drawtext(&dc, s, col); |  | ||||||
| 	for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++) |  | ||||||
| 		drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void | void | ||||||
| drawmenuh(void) { | drawmenuh(void) { | ||||||
| 	Item *i; | 	Item *i; | ||||||
|  | @ -202,7 +219,19 @@ drawmenuv(void) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| kpress(XKeyEvent *e) { | grabkeyboard(void) { | ||||||
|  | 	unsigned int n; | ||||||
|  | 
 | ||||||
|  | 	for(n = 0; n < 1000; n++) { | ||||||
|  | 		if(!XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) | ||||||
|  | 			return; | ||||||
|  | 		usleep(1000); | ||||||
|  | 	} | ||||||
|  | 	exit(EXIT_FAILURE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | keypress(XKeyEvent *e) { | ||||||
| 	char buf[sizeof text]; | 	char buf[sizeof text]; | ||||||
| 	int num; | 	int num; | ||||||
| 	unsigned int i, len; | 	unsigned int i, len; | ||||||
|  | @ -248,6 +277,9 @@ kpress(XKeyEvent *e) { | ||||||
| 		case XK_m: | 		case XK_m: | ||||||
| 			ksym = XK_Return; | 			ksym = XK_Return; | ||||||
| 			break; | 			break; | ||||||
|  | 		case XK_k: | ||||||
|  | 			text[cur] = '\0'; | ||||||
|  | 			break; | ||||||
| 		case XK_n: | 		case XK_n: | ||||||
| 			ksym = XK_Down; | 			ksym = XK_Down; | ||||||
| 			break; | 			break; | ||||||
|  | @ -255,38 +287,67 @@ kpress(XKeyEvent *e) { | ||||||
| 			ksym = XK_Up; | 			ksym = XK_Up; | ||||||
| 			break; | 			break; | ||||||
| 		case XK_u: | 		case XK_u: | ||||||
| 			text[0] = '\0'; | 			memmove(text, text + cur, sizeof text - cur + 1); | ||||||
|  | 			cur = 0; | ||||||
| 			match(); | 			match(); | ||||||
| 			break; | 			break; | ||||||
| 		case XK_w: | 		case XK_w: | ||||||
| 			if(len == 0) | 			if(cur == 0) | ||||||
| 				return; | 				return; | ||||||
| 			i = len; | 			i = cur; | ||||||
| 			while(i-- > 0 && text[i] == ' '); | 			while(i-- > 0 && text[i] == ' '); | ||||||
| 			while(i-- > 0 && text[i] != ' '); | 			while(i-- > 0 && text[i] != ' '); | ||||||
| 			text[++i] = '\0'; | 			memmove(text + i + 1, text + cur, sizeof text - cur + 1); | ||||||
|  | 			cur = i + 1; | ||||||
| 			match(); | 			match(); | ||||||
| 			break; | 			break; | ||||||
|  | 		case XK_y: | ||||||
|  | 			{ | ||||||
|  | 				FILE *fp; | ||||||
|  | 				char *s; | ||||||
|  | 				if(!(fp = fopen("sselp", "r"))) | ||||||
|  | 					eprint("cannot popen sselp\n"); | ||||||
|  | 				s = fgets(buf, sizeof buf, fp); | ||||||
|  | 				fclose(fp); | ||||||
|  | 				if(!s) | ||||||
|  | 					return; | ||||||
|  | 			} | ||||||
|  | 			num = strlen(buf); | ||||||
|  | 			if(num && buf[num-1] == '\n') | ||||||
|  | 				buf[--num] = '\0'; | ||||||
|  | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	switch(ksym) { | 	switch(ksym) { | ||||||
| 	default: | 	default: | ||||||
| 		num = MIN(num, sizeof text); | 		num = MIN(num, sizeof text); | ||||||
| 		if(num && !iscntrl((int) buf[0])) { | 		if(num && !iscntrl((int) buf[0])) { | ||||||
| 			memcpy(text + len, buf, num + 1); | 			memmove(text + cur + num, text + cur, sizeof text - cur - num); | ||||||
| 			len += num; | 			memcpy(text + cur, buf, num); | ||||||
|  | 			cur += num; | ||||||
| 			match(); | 			match(); | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case XK_BackSpace: | 	case XK_BackSpace: | ||||||
| 		if(len == 0) | 		if(cur == 0) | ||||||
| 			return; | 			return; | ||||||
| 		for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++); | 		for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[cur - i]); i++); | ||||||
| 		len -= i; | 		memmove(text + cur - i, text + cur, sizeof text - cur + i); | ||||||
| 		text[len] = '\0'; | 		cur -= i; | ||||||
|  | 		match(); | ||||||
|  | 		break; | ||||||
|  | 	case XK_Delete: | ||||||
|  | 		if(cur == len) | ||||||
|  | 			return; | ||||||
|  | 		for(i = 1; cur + i < len && !IS_UTF8_1ST_CHAR(text[cur + i]); i++); | ||||||
|  | 		memmove(text + cur, text + cur + i, sizeof text - cur); | ||||||
| 		match(); | 		match(); | ||||||
| 		break; | 		break; | ||||||
| 	case XK_End: | 	case XK_End: | ||||||
|  | 		if(cur < len) { | ||||||
|  | 			cur = len; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| 		while(next) { | 		while(next) { | ||||||
| 			sel = curr = next; | 			sel = curr = next; | ||||||
| 			calcoffsets(); | 			calcoffsets(); | ||||||
|  | @ -297,10 +358,20 @@ kpress(XKeyEvent *e) { | ||||||
| 	case XK_Escape: | 	case XK_Escape: | ||||||
| 		exit(EXIT_FAILURE); | 		exit(EXIT_FAILURE); | ||||||
| 	case XK_Home: | 	case XK_Home: | ||||||
|  | 		if(sel == item) { | ||||||
|  | 			cur = 0; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| 		sel = curr = item; | 		sel = curr = item; | ||||||
| 		calcoffsets(); | 		calcoffsets(); | ||||||
| 		break; | 		break; | ||||||
| 	case XK_Left: | 	case XK_Left: | ||||||
|  | 		if(cur > 0 && (!sel || !sel->left || lines > 0)) { | ||||||
|  | 			while(cur-- > 0 && !IS_UTF8_1ST_CHAR(text[cur])); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		if(lines > 0) | ||||||
|  | 			return; | ||||||
| 	case XK_Up: | 	case XK_Up: | ||||||
| 		if(!sel || !sel->left) | 		if(!sel || !sel->left) | ||||||
| 			return; | 			return; | ||||||
|  | @ -323,12 +394,16 @@ kpress(XKeyEvent *e) { | ||||||
| 		calcoffsets(); | 		calcoffsets(); | ||||||
| 		break; | 		break; | ||||||
| 	case XK_Return: | 	case XK_Return: | ||||||
| 		if(e->state & ShiftMask) | 		fprintf(stdout, "%s", ((e->state & ShiftMask) || sel) ? sel->text : text); | ||||||
| 			dinput(); |  | ||||||
| 		fprintf(stdout, "%s", sel ? sel->text : text); |  | ||||||
| 		fflush(stdout); | 		fflush(stdout); | ||||||
| 		exit(EXIT_SUCCESS); | 		exit(EXIT_SUCCESS); | ||||||
| 	case XK_Right: | 	case XK_Right: | ||||||
|  | 		if(cur < len) { | ||||||
|  | 			while(cur++ < len && !IS_UTF8_1ST_CHAR(text[cur])); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		if(lines > 0) | ||||||
|  | 			return; | ||||||
| 	case XK_Down: | 	case XK_Down: | ||||||
| 		if(!sel || !sel->right) | 		if(!sel || !sel->right) | ||||||
| 			return; | 			return; | ||||||
|  | @ -339,12 +414,14 @@ kpress(XKeyEvent *e) { | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case XK_Tab: | 	case XK_Tab: | ||||||
| 		if(sel) | 		if(!sel) | ||||||
| 			strncpy(text, sel->text, sizeof text); | 			return; | ||||||
| 		dinput(); | 		strncpy(text, sel->text, sizeof text); | ||||||
|  | 		cur = strlen(text); | ||||||
|  | 		match(); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 	drawbar(); | 	drawmenu(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  | @ -413,6 +490,98 @@ readstdin(void) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void | ||||||
|  | run(void) { | ||||||
|  | 	XEvent ev; | ||||||
|  | 
 | ||||||
|  | 	XSync(dpy, False); | ||||||
|  | 	while(!XNextEvent(dpy, &ev)) | ||||||
|  | 		switch(ev.type) { | ||||||
|  | 		case Expose: | ||||||
|  | 			if(ev.xexpose.count == 0) | ||||||
|  | 				drawmenu(); | ||||||
|  | 			break; | ||||||
|  | 		case KeyPress: | ||||||
|  | 			keypress(&ev.xkey); | ||||||
|  | 			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) * (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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int | int | ||||||
| main(int argc, char *argv[]) { | main(int argc, char *argv[]) { | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
|  | @ -472,7 +641,7 @@ main(int argc, char *argv[]) { | ||||||
| 
 | 
 | ||||||
| 	readstdin(); | 	readstdin(); | ||||||
| 	grabkeyboard(); | 	grabkeyboard(); | ||||||
| 	setup(lines); | 	setup(); | ||||||
| 	if(maxname) | 	if(maxname) | ||||||
| 		cmdw = MIN(textw(&dc, maxname), mw / 3); | 		cmdw = MIN(textw(&dc, maxname), mw / 3); | ||||||
| 	match(); | 	match(); | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								dmenu.h
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								dmenu.h
									
										
									
									
									
								
							|  | @ -1,30 +0,0 @@ | ||||||
| #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; |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue