merged dmenu & dinput (clunky interface) 7d5fe173
Connor Lane Smith · 2010-07-30 13:40 5 file(s) · +215 −440
Makefile +5 −10
3 3
4 4
include config.mk
5 5
6 -
SRC = dinput.c dmenu.c common.c
6 +
SRC = dmenu.c
7 7
OBJ = ${SRC:.c=.o}
8 8
9 9
all: options dinput dmenu
24 24
	@echo creating $@ from config.def.h
25 25
	@cp config.def.h $@
26 26
27 -
dinput: dinput.o common.o
28 -
	@echo CC -o $@
29 -
	@${CC} -o $@ $+ ${LDFLAGS}
30 -
31 -
dmenu: dmenu.o common.o
27 +
dmenu: ${OBJ}
32 28
	@echo CC -o $@
33 29
	@${CC} -o $@ $+ ${LDFLAGS}
34 30
35 31
clean:
36 32
	@echo cleaning
37 -
	@rm -f dinput dmenu ${OBJ} dmenu-${VERSION}.tar.gz
33 +
	@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
38 34
39 35
dist: clean
40 36
	@echo creating dist tarball
47 43
install: all
48 44
	@echo installing executable file to ${DESTDIR}${PREFIX}/bin
49 45
	@mkdir -p ${DESTDIR}${PREFIX}/bin
50 -
	@cp -f dinput dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
51 -
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dinput
46 +
	@cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
52 47
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
53 48
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
54 49
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
60 55
uninstall:
61 56
	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
62 57
	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
63 -
	@rm -f ${DESTDIR}${PREFIX}/bin/dinput ${DESTDIR}${PREFIX}/bin/dmenu_run
58 +
	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
64 59
	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
65 60
	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
66 61
common.c (deleted) +0 −129
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include <stdlib.h>
3 -
#include <string.h>
4 -
#include <unistd.h>
5 -
#include <X11/keysym.h>
6 -
#ifdef XINERAMA
7 -
#include <X11/extensions/Xinerama.h>
8 -
#endif
9 -
#include "dmenu.h"
10 -
11 -
/* variables */
12 -
char *prompt = NULL;
13 -
char text[4096] = "";
14 -
int promptw = 0;
15 -
int screen;
16 -
unsigned int numlockmask = 0;
17 -
unsigned int mw, mh;
18 -
unsigned long normcol[ColLast];
19 -
unsigned long selcol[ColLast];
20 -
Bool topbar = True;
21 -
DC dc;
22 -
Display *dpy;
23 -
Window win, root;
24 -
25 -
void
26 -
grabkeyboard(void) {
27 -
	unsigned int len;
28 -
29 -
	for(len = 1000; len; len--) {
30 -
		if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
31 -
		== GrabSuccess)
32 -
			return;
33 -
		usleep(1000);
34 -
	}
35 -
	exit(EXIT_FAILURE);
36 -
}
37 -
38 -
void
39 -
run(void) {
40 -
	XEvent ev;
41 -
42 -
	/* main event loop */
43 -
	XSync(dpy, False);
44 -
	while(!XNextEvent(dpy, &ev))
45 -
		switch(ev.type) {
46 -
		case KeyPress:
47 -
			kpress(&ev.xkey);
48 -
			break;
49 -
		case Expose:
50 -
			if(ev.xexpose.count == 0)
51 -
				drawbar();
52 -
			break;
53 -
		case VisibilityNotify:
54 -
			if(ev.xvisibility.state != VisibilityUnobscured)
55 -
				XRaiseWindow(dpy, win);
56 -
			break;
57 -
		}
58 -
	exit(EXIT_FAILURE);
59 -
}
60 -
61 -
void
62 -
setup(unsigned int lines) {
63 -
	int i, j, x, y;
64 -
#if XINERAMA
65 -
	int n;
66 -
	XineramaScreenInfo *info = NULL;
67 -
#endif
68 -
	XModifierKeymap *modmap;
69 -
	XSetWindowAttributes wa;
70 -
71 -
	/* init modifier map */
72 -
	modmap = XGetModifierMapping(dpy);
73 -
	for(i = 0; i < 8; i++)
74 -
		for(j = 0; j < modmap->max_keypermod; j++) {
75 -
			if(modmap->modifiermap[i * modmap->max_keypermod + j]
76 -
			== XKeysymToKeycode(dpy, XK_Num_Lock))
77 -
				numlockmask = (1 << i);
78 -
		}
79 -
	XFreeModifiermap(modmap);
80 -
81 -
	dc.dpy = dpy;
82 -
	normcol[ColBG] = getcolor(&dc, normbgcolor);
83 -
	normcol[ColFG] = getcolor(&dc, normfgcolor);
84 -
	selcol[ColBG] = getcolor(&dc, selbgcolor);
85 -
	selcol[ColFG] = getcolor(&dc, selfgcolor);
86 -
	initfont(&dc, font);
87 -
88 -
	/* input window */
89 -
	wa.override_redirect = True;
90 -
	wa.background_pixmap = ParentRelative;
91 -
	wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
92 -
93 -
	/* input window geometry */
94 -
	mh = (dc.font.height + 2) * (lines + 1);
95 -
#if XINERAMA
96 -
	if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
97 -
		i = 0;
98 -
		if(n > 1) {
99 -
			int di;
100 -
			unsigned int dui;
101 -
			Window dummy;
102 -
			if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
103 -
				for(i = 0; i < n; i++)
104 -
					if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
105 -
						break;
106 -
		}
107 -
		x = info[i].x_org;
108 -
		y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
109 -
		mw = info[i].width;
110 -
		XFree(info);
111 -
	}
112 -
	else
113 -
#endif
114 -
	{
115 -
		x = 0;
116 -
		y = topbar ? 0 : DisplayHeight(dpy, screen) - mh;
117 -
		mw = DisplayWidth(dpy, screen);
118 -
	}
119 -
120 -
	win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
121 -
			DefaultDepth(dpy, screen), CopyFromParent,
122 -
			DefaultVisual(dpy, screen),
123 -
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
124 -
125 -
	setupdraw(&dc, win);
126 -
	if(prompt)
127 -
		promptw = MIN(textw(&dc, prompt), mw / 5);
128 -
	XMapRaised(dpy, win);
129 -
}
dinput.c (deleted) +0 −230
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include <ctype.h>
3 -
#include <locale.h>
4 -
#include <stdio.h>
5 -
#include <stdlib.h>
6 -
#include <string.h>
7 -
#include <X11/keysym.h>
8 -
#include <X11/Xlib.h>
9 -
#include <X11/Xutil.h>
10 -
#include "dmenu.h"
11 -
12 -
/* forward declarations */
13 -
static void cleanup(void);
14 -
15 -
/* variables */
16 -
static size_t cursor = 0;
17 -
18 -
void
19 -
cleanup(void) {
20 -
	cleanupdraw(&dc);
21 -
	XDestroyWindow(dpy, win);
22 -
	XUngrabKeyboard(dpy, CurrentTime);
23 -
	XCloseDisplay(dpy);
24 -
}
25 -
26 -
void
27 -
drawbar(void)
28 -
{
29 -
	dc.x = 0;
30 -
	dc.y = 0;
31 -
	dc.w = mw;
32 -
	dc.h = mh;
33 -
	drawbox(&dc, normcol);
34 -
	/* print prompt? */
35 -
	if(prompt) {
36 -
		dc.w = promptw;
37 -
		drawbox(&dc, selcol);
38 -
		drawtext(&dc, prompt, selcol);
39 -
		dc.x += dc.w;
40 -
	}
41 -
	dc.w = mw - dc.x;
42 -
	drawtext(&dc, text, normcol);
43 -
	drawline(&dc, textnw(&dc, text, cursor) + dc.font.height/2, 2, 1,
44 -
			dc.font.height-2, normcol);
45 -
	commitdraw(&dc, win);
46 -
}
47 -
48 -
void
49 -
kpress(XKeyEvent *e) {
50 -
	char buf[sizeof text];
51 -
	int num;
52 -
	unsigned int i, len;
53 -
	KeySym ksym;
54 -
55 -
	len = strlen(text);
56 -
	num = XLookupString(e, buf, sizeof buf, &ksym, NULL);
57 -
	if(ksym == XK_KP_Enter)
58 -
		ksym = XK_Return;
59 -
	else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
60 -
		ksym = (ksym - XK_KP_0) + XK_0;
61 -
	else if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
62 -
	|| IsMiscFunctionKey(ksym) || IsPFKey(ksym)
63 -
	|| IsPrivateKeypadKey(ksym))
64 -
		return;
65 -
	/* first check if a control mask is omitted */
66 -
	if(e->state & ControlMask) {
67 -
		switch(tolower(ksym)) {
68 -
		default:
69 -
			return;
70 -
		case XK_a:
71 -
			ksym = XK_Home;
72 -
			break;
73 -
		case XK_b:
74 -
			ksym = XK_Left;
75 -
			break;
76 -
		case XK_c:
77 -
			ksym = XK_Escape;
78 -
			break;
79 -
		case XK_e:
80 -
			ksym = XK_End;
81 -
			break;
82 -
		case XK_f:
83 -
			ksym = XK_Right;
84 -
			break;
85 -
		case XK_h:
86 -
			ksym = XK_BackSpace;
87 -
			break;
88 -
		case XK_j:
89 -
		case XK_m:
90 -
			ksym = XK_Return;
91 -
			break;
92 -
		case XK_k:
93 -
			text[cursor] = '\0';
94 -
			break;
95 -
		case XK_u:
96 -
			memmove(text, text + cursor, sizeof text - cursor + 1);
97 -
			cursor = 0;
98 -
			break;
99 -
		case XK_w:
100 -
			if(cursor > 0) {
101 -
				i = cursor;
102 -
				while(i-- > 0 && text[i] == ' ');
103 -
				while(i-- > 0 && text[i] != ' ');
104 -
				memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
105 -
				cursor = i + 1;
106 -
			}
107 -
			break;
108 -
		case XK_y:
109 -
			{
110 -
				FILE *fp;
111 -
				char *s;
112 -
				if(!(fp = popen("sselp", "r")))
113 -
					eprint("cannot popen sselp\n");
114 -
				s = fgets(buf, sizeof buf, fp);
115 -
				pclose(fp);
116 -
				if(s == NULL)
117 -
					return;
118 -
			}
119 -
			num = strlen(buf);
120 -
			if(num && buf[num-1] == '\n')
121 -
				buf[--num] = '\0';
122 -
			break;
123 -
		}
124 -
	}
125 -
	switch(ksym) {
126 -
	default:
127 -
		num = MIN(num, sizeof text - cursor);
128 -
		if(num && !iscntrl((int) buf[0])) {
129 -
			memmove(text + cursor + num, text + cursor, sizeof text - cursor - num);
130 -
			memcpy(text + cursor, buf, num);
131 -
			cursor += num;
132 -
		}
133 -
		break;
134 -
	case XK_BackSpace:
135 -
		if(cursor == 0)
136 -
			return;
137 -
		for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++);
138 -
		memmove(text + cursor - i, text + cursor, sizeof text - cursor + i);
139 -
		cursor -= i;
140 -
		break;
141 -
	case XK_Delete:
142 -
		if(cursor == len)
143 -
			return;
144 -
		for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++);
145 -
		memmove(text + cursor, text + cursor + i, sizeof text - cursor);
146 -
		break;
147 -
	case XK_End:
148 -
		cursor = len;
149 -
		break;
150 -
	case XK_Escape:
151 -
		exit(EXIT_FAILURE);
152 -
	case XK_Home:
153 -
		cursor = 0;
154 -
		break;
155 -
	case XK_Left:
156 -
		if(cursor == 0)
157 -
			return;
158 -
		while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
159 -
		break;
160 -
	case XK_Return:
161 -
		fprintf(stdout, "%s", text);
162 -
		fflush(stdout);
163 -
		exit(EXIT_SUCCESS);
164 -
	case XK_Right:
165 -
		if(cursor == len)
166 -
			return;
167 -
		while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
168 -
		break;
169 -
	}
170 -
	drawbar();
171 -
}
172 -
173 -
int
174 -
main(int argc, char *argv[]) {
175 -
	unsigned int i;
176 -
177 -
	/* command line args */
178 -
	progname = "dinput";
179 -
	for(i = 1; i < argc; i++)
180 -
		if(!strcmp(argv[i], "-i"))
181 -
			;  /* ignore flag */
182 -
		else if(!strcmp(argv[i], "-b"))
183 -
			topbar = False;
184 -
		else if(!strcmp(argv[i], "-l"))
185 -
			i++;  /* ignore flag */
186 -
		else if(!strcmp(argv[i], "-fn")) {
187 -
			if(++i < argc) font = argv[i];
188 -
		}
189 -
		else if(!strcmp(argv[i], "-nb")) {
190 -
			if(++i < argc) normbgcolor = argv[i];
191 -
		}
192 -
		else if(!strcmp(argv[i], "-nf")) {
193 -
			if(++i < argc) normfgcolor = argv[i];
194 -
		}
195 -
		else if(!strcmp(argv[i], "-p")) {
196 -
			if(++i < argc) prompt = argv[i];
197 -
		}
198 -
		else if(!strcmp(argv[i], "-sb")) {
199 -
			if(++i < argc) selbgcolor = argv[i];
200 -
		}
201 -
		else if(!strcmp(argv[i], "-sf")) {
202 -
			if(++i < argc) selfgcolor = argv[i];
203 -
		}
204 -
		else if(!strcmp(argv[i], "-v")) {
205 -
			printf("dinput-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n");
206 -
			exit(EXIT_SUCCESS);
207 -
		}
208 -
		else if(!*text) {
209 -
			strncpy(text, argv[i], sizeof text);
210 -
			cursor = strlen(text);
211 -
		}
212 -
		else {
213 -
			fputs("usage: dinput [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
214 -
			      "              [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n", stderr);
215 -
			exit(EXIT_FAILURE);
216 -
		}
217 -
	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
218 -
		fprintf(stderr, "dinput: warning: no locale support\n");
219 -
	if(!(dpy = XOpenDisplay(NULL)))
220 -
		eprint("cannot open display\n");
221 -
	if(atexit(&cleanup) != 0)
222 -
		eprint("cannot register cleanup\n");
223 -
	screen = DefaultScreen(dpy);
224 -
	root = RootWindow(dpy, screen);
225 -
226 -
	grabkeyboard();
227 -
	setup(0);
228 -
	run();
229 -
	return 0;
230 -
}
dmenu.c +210 −41
8 8
#include <X11/keysym.h>
9 9
#include <X11/Xlib.h>
10 10
#include <X11/Xutil.h>
11 -
#include "dmenu.h"
11 +
#ifdef XINERAMA
12 +
#include <X11/extensions/Xinerama.h>
13 +
#endif
14 +
#include <draw.h>
15 +
#include "config.h"
16 +
17 +
#define INRECT(x,y,rx,ry,rw,rh) ((rx) < (x) && (x) < (rx)+(rw) && (ry) < (y) && (y) < (ry)+(rh))
18 +
#define MIN(a,b)                ((a) < (b) ? (a) : (b))
19 +
#define MAX(a,b)                ((a) > (b) ? (a) : (b))
20 +
#define IS_UTF8_1ST_CHAR(c)     (((c) & 0xc0) == 0xc0 || ((c) & 0x80) == 0x00)
12 21
13 22
typedef struct Item Item;
14 23
struct Item {
17 26
	Item *left, *right; /* traverses items matching current search pattern */
18 27
};
19 28
20 -
/* forward declarations */
21 29
static void appenditem(Item *i, Item **list, Item **last);
22 30
static void calcoffsetsh(void);
23 31
static void calcoffsetsv(void);
24 32
static char *cistrstr(const char *s, const char *sub);
25 33
static void cleanup(void);
26 -
static void dinput(void);
27 34
static void drawitem(const char *s, unsigned long col[ColLast]);
35 +
static void drawmenu(void);
28 36
static void drawmenuh(void);
29 37
static void drawmenuv(void);
38 +
static void grabkeyboard(void);
39 +
static void keypress(XKeyEvent *e);
30 40
static void match(void);
31 41
static void readstdin(void);
42 +
static void run(void);
43 +
static void setup(void);
32 44
33 -
/* variables */
34 45
static char **argp = NULL;
35 46
static char *maxname = NULL;
47 +
static char *prompt;
48 +
static char text[4096];
49 +
static int promptw;
50 +
static int screen;
51 +
static size_t cur = 0;
36 52
static unsigned int cmdw = 0;
37 53
static unsigned int lines = 0;
54 +
static unsigned int numlockmask;
55 +
static unsigned int mw, mh;
56 +
static unsigned long normcol[ColLast];
57 +
static unsigned long selcol[ColLast];
58 +
static Bool topbar = True;
59 +
static DC dc;
60 +
static Display *dpy;
38 61
static Item *allitems = NULL;  /* first of all items */
39 62
static Item *item = NULL;      /* first of pattern matching items */
40 63
static Item *sel = NULL;
41 64
static Item *next = NULL;
42 65
static Item *prev = NULL;
43 66
static Item *curr = NULL;
67 +
static Window win, root;
68 +
44 69
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
45 70
static char *(*fstrstr)(const char *, const char *) = strstr;
46 71
static void (*calcoffsets)(void) = calcoffsetsh;
120 145
}
121 146
122 147
void
123 -
dinput(void) {
124 -
	cleanup();
125 -
	argp[0] = "dinput";
126 -
	argp[1] = text;
127 -
	execvp("dinput", argp);
128 -
	eprint("cannot exec dinput\n");
148 +
drawitem(const char *s, unsigned long col[ColLast]) {
149 +
	const char *p;
150 +
	unsigned int w = textnw(&dc, text, strlen(text));
151 +
152 +
	drawbox(&dc, col);
153 +
	drawtext(&dc, s, col);
154 +
	for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++)
155 +
		drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col);
129 156
}
130 157
131 158
void
132 -
drawbar(void) {
159 +
drawmenu(void) {
133 160
	dc.x = 0;
134 161
	dc.y = 0;
135 162
	dc.w = mw;
149 176
	if(cmdw && item && lines == 0)
150 177
		dc.w = cmdw;
151 178
	drawtext(&dc, text, normcol);
179 +
	drawline(&dc, textnw(&dc, text, cur) + dc.h/2 - 2, 2, 1, dc.h-4, normcol);
152 180
	if(lines > 0)
153 181
		drawmenuv();
154 182
	else if(curr)
155 183
		drawmenuh();
156 184
	commitdraw(&dc, win);
157 -
}
158 -
159 -
void
160 -
drawitem(const char *s, unsigned long col[ColLast]) {
161 -
	const char *p;
162 -
	unsigned int w = textnw(&dc, text, strlen(text));
163 -
164 -
	drawbox(&dc, col);
165 -
	drawtext(&dc, s, col);
166 -
	for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++)
167 -
		drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col);
168 185
}
169 186
170 187
void
202 219
}
203 220
204 221
void
205 -
kpress(XKeyEvent *e) {
222 +
grabkeyboard(void) {
223 +
	unsigned int n;
224 +
225 +
	for(n = 0; n < 1000; n++) {
226 +
		if(!XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime))
227 +
			return;
228 +
		usleep(1000);
229 +
	}
230 +
	exit(EXIT_FAILURE);
231 +
}
232 +
233 +
void
234 +
keypress(XKeyEvent *e) {
206 235
	char buf[sizeof text];
207 236
	int num;
208 237
	unsigned int i, len;
248 277
		case XK_m:
249 278
			ksym = XK_Return;
250 279
			break;
280 +
		case XK_k:
281 +
			text[cur] = '\0';
282 +
			break;
251 283
		case XK_n:
252 284
			ksym = XK_Down;
253 285
			break;
255 287
			ksym = XK_Up;
256 288
			break;
257 289
		case XK_u:
258 -
			text[0] = '\0';
290 +
			memmove(text, text + cur, sizeof text - cur + 1);
291 +
			cur = 0;
259 292
			match();
260 293
			break;
261 294
		case XK_w:
262 -
			if(len == 0)
295 +
			if(cur == 0)
263 296
				return;
264 -
			i = len;
297 +
			i = cur;
265 298
			while(i-- > 0 && text[i] == ' ');
266 299
			while(i-- > 0 && text[i] != ' ');
267 -
			text[++i] = '\0';
300 +
			memmove(text + i + 1, text + cur, sizeof text - cur + 1);
301 +
			cur = i + 1;
268 302
			match();
269 303
			break;
304 +
		case XK_y:
305 +
			{
306 +
				FILE *fp;
307 +
				char *s;
308 +
				if(!(fp = fopen("sselp", "r")))
309 +
					eprint("cannot popen sselp\n");
310 +
				s = fgets(buf, sizeof buf, fp);
311 +
				fclose(fp);
312 +
				if(!s)
313 +
					return;
314 +
			}
315 +
			num = strlen(buf);
316 +
			if(num && buf[num-1] == '\n')
317 +
				buf[--num] = '\0';
318 +
			break;
270 319
		}
271 320
	}
272 321
	switch(ksym) {
273 322
	default:
274 323
		num = MIN(num, sizeof text);
275 324
		if(num && !iscntrl((int) buf[0])) {
276 -
			memcpy(text + len, buf, num + 1);
277 -
			len += num;
325 +
			memmove(text + cur + num, text + cur, sizeof text - cur - num);
326 +
			memcpy(text + cur, buf, num);
327 +
			cur += num;
278 328
			match();
279 329
		}
280 330
		break;
281 331
	case XK_BackSpace:
282 -
		if(len == 0)
332 +
		if(cur == 0)
333 +
			return;
334 +
		for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[cur - i]); i++);
335 +
		memmove(text + cur - i, text + cur, sizeof text - cur + i);
336 +
		cur -= i;
337 +
		match();
338 +
		break;
339 +
	case XK_Delete:
340 +
		if(cur == len)
283 341
			return;
284 -
		for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++);
285 -
		len -= i;
286 -
		text[len] = '\0';
342 +
		for(i = 1; cur + i < len && !IS_UTF8_1ST_CHAR(text[cur + i]); i++);
343 +
		memmove(text + cur, text + cur + i, sizeof text - cur);
287 344
		match();
288 345
		break;
289 346
	case XK_End:
347 +
		if(cur < len) {
348 +
			cur = len;
349 +
			break;
350 +
		}
290 351
		while(next) {
291 352
			sel = curr = next;
292 353
			calcoffsets();
297 358
	case XK_Escape:
298 359
		exit(EXIT_FAILURE);
299 360
	case XK_Home:
361 +
		if(sel == item) {
362 +
			cur = 0;
363 +
			break;
364 +
		}
300 365
		sel = curr = item;
301 366
		calcoffsets();
302 367
		break;
303 368
	case XK_Left:
369 +
		if(cur > 0 && (!sel || !sel->left || lines > 0)) {
370 +
			while(cur-- > 0 && !IS_UTF8_1ST_CHAR(text[cur]));
371 +
			break;
372 +
		}
373 +
		if(lines > 0)
374 +
			return;
304 375
	case XK_Up:
305 376
		if(!sel || !sel->left)
306 377
			return;
323 394
		calcoffsets();
324 395
		break;
325 396
	case XK_Return:
326 -
		if(e->state & ShiftMask)
327 -
			dinput();
328 -
		fprintf(stdout, "%s", sel ? sel->text : text);
397 +
		fprintf(stdout, "%s", ((e->state & ShiftMask) || sel) ? sel->text : text);
329 398
		fflush(stdout);
330 399
		exit(EXIT_SUCCESS);
331 400
	case XK_Right:
401 +
		if(cur < len) {
402 +
			while(cur++ < len && !IS_UTF8_1ST_CHAR(text[cur]));
403 +
			break;
404 +
		}
405 +
		if(lines > 0)
406 +
			return;
332 407
	case XK_Down:
333 408
		if(!sel || !sel->right)
334 409
			return;
339 414
		}
340 415
		break;
341 416
	case XK_Tab:
342 -
		if(sel)
343 -
			strncpy(text, sel->text, sizeof text);
344 -
		dinput();
417 +
		if(!sel)
418 +
			return;
419 +
		strncpy(text, sel->text, sizeof text);
420 +
		cur = strlen(text);
421 +
		match();
345 422
		break;
346 423
	}
347 -
	drawbar();
424 +
	drawmenu();
348 425
}
349 426
350 427
void
413 490
	}
414 491
}
415 492
493 +
void
494 +
run(void) {
495 +
	XEvent ev;
496 +
497 +
	XSync(dpy, False);
498 +
	while(!XNextEvent(dpy, &ev))
499 +
		switch(ev.type) {
500 +
		case Expose:
501 +
			if(ev.xexpose.count == 0)
502 +
				drawmenu();
503 +
			break;
504 +
		case KeyPress:
505 +
			keypress(&ev.xkey);
506 +
			break;
507 +
		case VisibilityNotify:
508 +
			if(ev.xvisibility.state != VisibilityUnobscured)
509 +
				XRaiseWindow(dpy, win);
510 +
			break;
511 +
		}
512 +
	exit(EXIT_FAILURE);
513 +
}
514 +
515 +
void
516 +
setup(void) {
517 +
	int i, j, x, y;
518 +
#if XINERAMA
519 +
	int n;
520 +
	XineramaScreenInfo *info = NULL;
521 +
#endif
522 +
	XModifierKeymap *modmap;
523 +
	XSetWindowAttributes wa;
524 +
525 +
	/* init modifier map */
526 +
	modmap = XGetModifierMapping(dpy);
527 +
	for(i = 0; i < 8; i++)
528 +
		for(j = 0; j < modmap->max_keypermod; j++) {
529 +
			if(modmap->modifiermap[i * modmap->max_keypermod + j]
530 +
			== XKeysymToKeycode(dpy, XK_Num_Lock))
531 +
				numlockmask = (1 << i);
532 +
		}
533 +
	XFreeModifiermap(modmap);
534 +
535 +
	dc.dpy = dpy;
536 +
	normcol[ColBG] = getcolor(&dc, normbgcolor);
537 +
	normcol[ColFG] = getcolor(&dc, normfgcolor);
538 +
	selcol[ColBG] = getcolor(&dc, selbgcolor);
539 +
	selcol[ColFG] = getcolor(&dc, selfgcolor);
540 +
	initfont(&dc, font);
541 +
542 +
	/* input window */
543 +
	wa.override_redirect = True;
544 +
	wa.background_pixmap = ParentRelative;
545 +
	wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
546 +
547 +
	/* input window geometry */
548 +
	mh = (dc.font.height + 2) * (lines + 1);
549 +
#if XINERAMA
550 +
	if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
551 +
		i = 0;
552 +
		if(n > 1) {
553 +
			int di;
554 +
			unsigned int dui;
555 +
			Window dummy;
556 +
			if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
557 +
				for(i = 0; i < n; i++)
558 +
					if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
559 +
						break;
560 +
		}
561 +
		x = info[i].x_org;
562 +
		y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
563 +
		mw = info[i].width;
564 +
		XFree(info);
565 +
	}
566 +
	else
567 +
#endif
568 +
	{
569 +
		x = 0;
570 +
		y = topbar ? 0 : DisplayHeight(dpy, screen) - mh;
571 +
		mw = DisplayWidth(dpy, screen);
572 +
	}
573 +
574 +
	win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
575 +
			DefaultDepth(dpy, screen), CopyFromParent,
576 +
			DefaultVisual(dpy, screen),
577 +
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
578 +
579 +
	setupdraw(&dc, win);
580 +
	if(prompt)
581 +
		promptw = MIN(textw(&dc, prompt), mw / 5);
582 +
	XMapRaised(dpy, win);
583 +
}
584 +
416 585
int
417 586
main(int argc, char *argv[]) {
418 587
	unsigned int i;
472 641
473 642
	readstdin();
474 643
	grabkeyboard();
475 -
	setup(lines);
644 +
	setup();
476 645
	if(maxname)
477 646
		cmdw = MIN(textw(&dc, maxname), mw / 3);
478 647
	match();
dmenu.h (deleted) +0 −30
1 -
#include <X11/Xlib.h>
2 -
#include <draw.h>
3 -
#include "config.h"
4 -
5 -
/* macros */
6 -
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
7 -
#define MIN(a, b)               ((a) < (b) ? (a) : (b))
8 -
#define MAX(a, b)               ((a) > (b) ? (a) : (b))
9 -
#define IS_UTF8_1ST_CHAR(c)     ((((c) & 0xc0) == 0xc0) || !((c) & 0x80))
10 -
11 -
/* forward declarations */
12 -
void drawbar(void);
13 -
void grabkeyboard(void);
14 -
void kpress(XKeyEvent *e);
15 -
void run(void);
16 -
void setup(unsigned int lines);
17 -
18 -
/* variables */
19 -
extern char *prompt;
20 -
extern char text[4096];
21 -
extern int promptw;
22 -
extern int screen;
23 -
extern unsigned int numlockmask;
24 -
extern unsigned int mw, mh;
25 -
extern unsigned long normcol[ColLast];
26 -
extern unsigned long selcol[ColLast];
27 -
extern Bool topbar;
28 -
extern DC dc;
29 -
extern Display *dpy;
30 -
extern Window win, root;