initial dmenu / dinput separation
This commit is contained in:
		
							
								
								
									
										17
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Makefile
									
									
									
									
									
								
							@@ -3,10 +3,10 @@
 | 
			
		||||
 | 
			
		||||
include config.mk
 | 
			
		||||
 | 
			
		||||
SRC = dmenu.c
 | 
			
		||||
SRC = dinput.c dmenu.c draw.c
 | 
			
		||||
OBJ = ${SRC:.c=.o}
 | 
			
		||||
 | 
			
		||||
all: options dmenu
 | 
			
		||||
all: options dinput dmenu
 | 
			
		||||
 | 
			
		||||
options:
 | 
			
		||||
	@echo dmenu build options:
 | 
			
		||||
@@ -18,19 +18,19 @@ options:
 | 
			
		||||
	@echo CC $<
 | 
			
		||||
	@${CC} -c ${CFLAGS} $<
 | 
			
		||||
 | 
			
		||||
${OBJ}: config.h config.mk
 | 
			
		||||
${OBJ}: config.h config.mk draw.c
 | 
			
		||||
 | 
			
		||||
config.h:
 | 
			
		||||
	@echo creating $@ from config.def.h
 | 
			
		||||
	@cp config.def.h $@
 | 
			
		||||
 | 
			
		||||
dmenu: ${OBJ}
 | 
			
		||||
.o:
 | 
			
		||||
	@echo CC -o $@
 | 
			
		||||
	@${CC} -o $@ ${OBJ} ${LDFLAGS}
 | 
			
		||||
	@${CC} -o $@ $< ${LDFLAGS}
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	@echo cleaning
 | 
			
		||||
	@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
 | 
			
		||||
	@rm -f dinput dmenu ${OBJ} dmenu-${VERSION}.tar.gz
 | 
			
		||||
 | 
			
		||||
dist: clean
 | 
			
		||||
	@echo creating dist tarball
 | 
			
		||||
@@ -43,7 +43,8 @@ dist: clean
 | 
			
		||||
install: all
 | 
			
		||||
	@echo installing executable file to ${DESTDIR}${PREFIX}/bin
 | 
			
		||||
	@mkdir -p ${DESTDIR}${PREFIX}/bin
 | 
			
		||||
	@cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
 | 
			
		||||
	@cp -f dinput 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_path
 | 
			
		||||
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
			
		||||
@@ -55,7 +56,7 @@ install: all
 | 
			
		||||
uninstall:
 | 
			
		||||
	@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_run
 | 
			
		||||
	@rm -f ${DESTDIR}${PREFIX}/bin/dinput ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
			
		||||
	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
 | 
			
		||||
	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										387
									
								
								dinput.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								dinput.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,387 @@
 | 
			
		||||
/* See LICENSE file for copyright and license details. */
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <X11/keysym.h>
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#ifdef XINERAMA
 | 
			
		||||
#include <X11/extensions/Xinerama.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* macros */
 | 
			
		||||
#define CLEANMASK(mask)         (mask & ~(numlockmask | LockMask))
 | 
			
		||||
#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 */
 | 
			
		||||
static void cleanup(void);
 | 
			
		||||
static void drawcursor(void);
 | 
			
		||||
static void drawinput(void);
 | 
			
		||||
static void eprint(const char *errstr, ...);
 | 
			
		||||
static Bool grabkeyboard(void);
 | 
			
		||||
static void kpress(XKeyEvent * e);
 | 
			
		||||
static void run(void);
 | 
			
		||||
static void setup(Bool topbar);
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
/* variables */
 | 
			
		||||
static char *prompt = NULL;
 | 
			
		||||
static char text[4096];
 | 
			
		||||
static int promptw = 0;
 | 
			
		||||
static int ret = 0;
 | 
			
		||||
static int screen;
 | 
			
		||||
static unsigned int mw, mh;
 | 
			
		||||
static unsigned int cursor = 0;
 | 
			
		||||
static unsigned int numlockmask = 0;
 | 
			
		||||
static Bool running = True;
 | 
			
		||||
static Display *dpy;
 | 
			
		||||
static Window parent, win;
 | 
			
		||||
 | 
			
		||||
#include "draw.c"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
cleanup(void) {
 | 
			
		||||
	dccleanup();
 | 
			
		||||
	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
 | 
			
		||||
drawinput(void)
 | 
			
		||||
{
 | 
			
		||||
	dc.x = 0;
 | 
			
		||||
	dc.y = 0;
 | 
			
		||||
	dc.w = mw;
 | 
			
		||||
	dc.h = mh;
 | 
			
		||||
	drawtext(NULL, dc.norm);
 | 
			
		||||
	/* print prompt? */
 | 
			
		||||
	if(prompt) {
 | 
			
		||||
		dc.w = promptw;
 | 
			
		||||
		drawtext(prompt, dc.sel);
 | 
			
		||||
		dc.x += dc.w;
 | 
			
		||||
	}
 | 
			
		||||
	dc.w = mw - dc.x;
 | 
			
		||||
	drawtext(*text ? text : NULL, dc.norm);
 | 
			
		||||
	drawcursor();
 | 
			
		||||
	XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
 | 
			
		||||
	XFlush(dpy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eprint(const char *errstr, ...) {
 | 
			
		||||
	va_list ap;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, errstr);
 | 
			
		||||
	vfprintf(stderr, errstr, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bool
 | 
			
		||||
grabkeyboard(void) {
 | 
			
		||||
	unsigned int len;
 | 
			
		||||
 | 
			
		||||
	for(len = 1000; len; len--) {
 | 
			
		||||
		if(XGrabKeyboard(dpy, parent, True, GrabModeAsync, GrabModeAsync, CurrentTime)
 | 
			
		||||
		== GrabSuccess)
 | 
			
		||||
			break;
 | 
			
		||||
		usleep(1000);
 | 
			
		||||
	}
 | 
			
		||||
	return len > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
			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("dinput: 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:
 | 
			
		||||
		ret = 1;
 | 
			
		||||
		running = False;
 | 
			
		||||
		return;
 | 
			
		||||
	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);
 | 
			
		||||
		running = False;
 | 
			
		||||
		return;
 | 
			
		||||
	case XK_Right:
 | 
			
		||||
		if(cursor == len)
 | 
			
		||||
			return;
 | 
			
		||||
		while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	drawinput();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
run(void) {
 | 
			
		||||
	XEvent ev;
 | 
			
		||||
 | 
			
		||||
	/* main event loop */
 | 
			
		||||
	while(running && !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;
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
setup(Bool topbar) {
 | 
			
		||||
	int i, j, x, y;
 | 
			
		||||
#if XINERAMA
 | 
			
		||||
	int n;
 | 
			
		||||
	XineramaScreenInfo *info = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
	XModifierKeymap *modmap;
 | 
			
		||||
	XSetWindowAttributes wa;
 | 
			
		||||
	XWindowAttributes pwa;
 | 
			
		||||
 | 
			
		||||
	/* 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);
 | 
			
		||||
 | 
			
		||||
	/* 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 */
 | 
			
		||||
	wa.override_redirect = True;
 | 
			
		||||
	wa.background_pixmap = ParentRelative;
 | 
			
		||||
	wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | VisibilityChangeMask;
 | 
			
		||||
 | 
			
		||||
	/* menu window geometry */
 | 
			
		||||
	mh = (dc.font.height + 2);
 | 
			
		||||
#if XINERAMA
 | 
			
		||||
	if(parent == RootWindow(dpy, screen) && XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
 | 
			
		||||
		i = 0;
 | 
			
		||||
		if(n > 1) {
 | 
			
		||||
			int di;
 | 
			
		||||
			unsigned int dui;
 | 
			
		||||
			Window dummy;
 | 
			
		||||
			if(XQueryPointer(dpy, parent, &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
 | 
			
		||||
	{
 | 
			
		||||
		XGetWindowAttributes(dpy, parent, &pwa);
 | 
			
		||||
		x = 0;
 | 
			
		||||
		y = topbar ? 0 : pwa.height - mh;
 | 
			
		||||
		mw = pwa.width;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	win = XCreateWindow(dpy, parent, x, y, mw, mh, 0,
 | 
			
		||||
			DefaultDepth(dpy, screen), CopyFromParent,
 | 
			
		||||
			DefaultVisual(dpy, screen),
 | 
			
		||||
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
 | 
			
		||||
 | 
			
		||||
	/* pixmap */
 | 
			
		||||
	dcsetup();
 | 
			
		||||
	if(prompt)
 | 
			
		||||
		promptw = MIN(textw(prompt), mw / 5);
 | 
			
		||||
	cursor = strlen(text);
 | 
			
		||||
	XMapRaised(dpy, win);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int argc, char *argv[]) {
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	Bool topbar = True;
 | 
			
		||||
 | 
			
		||||
	/* command line args */
 | 
			
		||||
	for(i = 1; i < argc; i++)
 | 
			
		||||
		if(!strcmp(argv[i], "-b"))
 | 
			
		||||
			topbar = False;
 | 
			
		||||
		else if(!strcmp(argv[i], "-e")) {
 | 
			
		||||
			if(++i < argc) parent = atoi(argv[i]);
 | 
			
		||||
		}
 | 
			
		||||
		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"))
 | 
			
		||||
			eprint("dinput-"VERSION", © 2006-2010 dinput engineers, see LICENSE for details\n");
 | 
			
		||||
		else if(!*text)
 | 
			
		||||
			strncpy(text, argv[i], sizeof text);
 | 
			
		||||
		else
 | 
			
		||||
			eprint("usage: dinput [-b] [-e <xid>] [-fn <font>] [-nb <color>] [-nf <color>]\n"
 | 
			
		||||
			       "              [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n");
 | 
			
		||||
	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 | 
			
		||||
		fprintf(stderr, "dinput: warning: no locale support\n");
 | 
			
		||||
	if(!(dpy = XOpenDisplay(NULL)))
 | 
			
		||||
		eprint("dinput: cannot open display\n");
 | 
			
		||||
	screen = DefaultScreen(dpy);
 | 
			
		||||
	if(!parent)
 | 
			
		||||
		parent = RootWindow(dpy, screen);
 | 
			
		||||
 | 
			
		||||
	running = grabkeyboard();
 | 
			
		||||
	setup(topbar);
 | 
			
		||||
	drawinput();
 | 
			
		||||
	XSync(dpy, False);
 | 
			
		||||
	run();
 | 
			
		||||
	cleanup();
 | 
			
		||||
	XCloseDisplay(dpy);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										213
									
								
								dmenu.c
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								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,22 +34,16 @@ 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"
 | 
			
		||||
 | 
			
		||||
@@ -81,11 +56,9 @@ static int promptw = 0;
 | 
			
		||||
static int ret = 0;
 | 
			
		||||
static int screen;
 | 
			
		||||
static unsigned int mw, mh;
 | 
			
		||||
static unsigned int cursor = 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;
 | 
			
		||||
@@ -98,6 +71,8 @@ static char *(*fstrstr)(const char *, const char *) = strstr;
 | 
			
		||||
static unsigned int lines = 0;
 | 
			
		||||
static void (*calcoffsets)(void) = calcoffsetsh;
 | 
			
		||||
 | 
			
		||||
#include "draw.c"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
appenditem(Item *i, Item **list, Item **last) {
 | 
			
		||||
	if(!(*last))
 | 
			
		||||
@@ -161,26 +136,11 @@ 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);
 | 
			
		||||
	dccleanup();
 | 
			
		||||
	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 +159,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,34 +202,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;
 | 
			
		||||
@@ -281,16 +212,6 @@ eprint(const char *errstr, ...) {
 | 
			
		||||
	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 +225,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 +271,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 +278,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;
 | 
			
		||||
			if(len == 0)
 | 
			
		||||
				return;
 | 
			
		||||
			i = len;
 | 
			
		||||
			while(i-- > 0 && text[i] == ' ');
 | 
			
		||||
			while(i-- > 0 && text[i] != ' ');
 | 
			
		||||
				memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
 | 
			
		||||
				cursor = i + 1;
 | 
			
		||||
			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 +326,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 || lines > 0)) {
 | 
			
		||||
			while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if(lines > 0)
 | 
			
		||||
			return;
 | 
			
		||||
	case XK_Up:
 | 
			
		||||
		if(!sel || !sel->left)
 | 
			
		||||
			return;
 | 
			
		||||
@@ -508,12 +360,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 +373,6 @@ kpress(XKeyEvent * e) {
 | 
			
		||||
		if(!sel)
 | 
			
		||||
			return;
 | 
			
		||||
		strncpy(text, sel->text, sizeof text);
 | 
			
		||||
		cursor = strlen(text);
 | 
			
		||||
		match(text);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
@@ -690,11 +535,7 @@ setup(Bool topbar) {
 | 
			
		||||
			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);
 | 
			
		||||
	dcsetup();
 | 
			
		||||
	if(maxname)
 | 
			
		||||
		cmdw = MIN(textw(maxname), mw / 3);
 | 
			
		||||
	if(prompt)
 | 
			
		||||
@@ -704,22 +545,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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										143
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
/* See LICENSE file for copyright and license details. */
 | 
			
		||||
 | 
			
		||||
/* 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 */
 | 
			
		||||
 | 
			
		||||
/* forward declarations */
 | 
			
		||||
static void dccleanup(void);
 | 
			
		||||
static void dcsetup(void);
 | 
			
		||||
static void drawtext(const char *text, unsigned long col[ColLast]);
 | 
			
		||||
static unsigned long getcolor(const char *colstr);
 | 
			
		||||
static void initfont(const char *fontstr);
 | 
			
		||||
static int textnw(const char *text, unsigned int len);
 | 
			
		||||
static int textw(const char *text);
 | 
			
		||||
 | 
			
		||||
static DC dc;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
dccleanup(void) {
 | 
			
		||||
	if(dc.font.set)
 | 
			
		||||
		XFreeFontSet(dpy, dc.font.set);
 | 
			
		||||
	else
 | 
			
		||||
		XFreeFont(dpy, dc.font.xfont);
 | 
			
		||||
	XFreePixmap(dpy, dc.drawable);
 | 
			
		||||
	XFreeGC(dpy, dc.gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
dcsetup() {
 | 
			
		||||
	/* style */
 | 
			
		||||
	dc.norm[ColBG] = getcolor(normbgcolor);
 | 
			
		||||
	dc.norm[ColFG] = getcolor(normfgcolor);
 | 
			
		||||
	dc.sel[ColBG] = getcolor(selbgcolor);
 | 
			
		||||
	dc.sel[ColFG] = getcolor(selfgcolor);
 | 
			
		||||
	initfont(font);
 | 
			
		||||
 | 
			
		||||
	/* 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long
 | 
			
		||||
getcolor(const char *colstr) {
 | 
			
		||||
	Colormap cmap = DefaultColormap(dpy, screen);
 | 
			
		||||
	XColor color;
 | 
			
		||||
 | 
			
		||||
	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 | 
			
		||||
		eprint("drawtext: cannot allocate color '%s'\n", colstr);
 | 
			
		||||
	return color.pixel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
initfont(const char *fontstr) {
 | 
			
		||||
	char *def, **missing = NULL;
 | 
			
		||||
	int i, n;
 | 
			
		||||
 | 
			
		||||
	if(!fontstr || fontstr[0] == '\0')
 | 
			
		||||
		eprint("drawtext: 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("drawtext: 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user