applied cursor, vertical and paste patches for upcoming 4.1 dmenu version (due to the fact that surf is using dmenu as well) 569a1f92
Anselm R Garbe · 2009-11-28 12:28 4 file(s) · +149 −28
LICENSE +4 −1
1 1
MIT/X Consortium License
2 2
3 -
© 2006-2008 Anselm R. Garbe <garbeam at gmail dot com>
3 +
© 2006-2009 Anselm R. Garbe <anselm@garbe.us>
4 +
© 2009 Gottox <gottox@s01.de>
5 +
© 2009 Markus Schnalke <meillo@marmaro.de>
6 +
© 2009 Evan Gates <evan.gates@gmail.com>
4 7
© 2006-2008 Sander van Dijk <a dot h dot vandijk at gmail dot com>
5 8
© 2006-2007 Michał Janeczek <janeczek at gmail dot com>
6 9
config.mk +1 −1
1 1
# dmenu version
2 -
VERSION = 4.0
2 +
VERSION = 4.1
3 3
4 4
# Customize below to fit your system
5 5
dmenu.1 +6 −1
5 5
.B dmenu
6 6
.RB [ \-i ]
7 7
.RB [ \-b ]
8 +
.RB [ \-l " <lines>"]
8 9
.RB [ \-fn " <font>"]
9 10
.RB [ \-nb " <color>"]
10 11
.RB [ \-nf " <color>"]
25 26
.TP
26 27
.B \-b
27 28
defines that dmenu appears at the bottom.
29 +
.TP
30 +
.B \-l <lines>
31 +
activates vertical list mode.
32 +
The given number of lines will be displayed. Window height will get adjusted.
28 33
.TP
29 34
.B \-fn <font>
30 35
defines the font.
57 62
Appends the character to the text in the input field.  This works as a filter:
58 63
only items containing this text will be displayed.
59 64
.TP
60 -
.B Left/Right (Mod1\-h/Mod1\-l)
65 +
.B Left/Right (Up/Down) (Mod1\-h/Mod1\-l)
61 66
Select the previous/next item.
62 67
.TP
63 68
.B PageUp/PageDown (Mod1\-k/Mod1\-j)
dmenu.c +138 −25
18 18
#define CLEANMASK(mask)         (mask & ~(numlockmask | LockMask))
19 19
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
20 20
#define MIN(a, b)               ((a) < (b) ? (a) : (b))
21 +
#define MAX(a, b)               ((a) > (b) ? (a) : (b))
21 22
22 23
/* enums */
23 24
enum { ColFG, ColBG, ColLast };
47 48
48 49
/* forward declarations */
49 50
static void appenditem(Item *i, Item **list, Item **last);
50 -
static void calcoffsets(void);
51 +
static void calcoffsetsh(void);
52 +
static void calcoffsetsv(void);
51 53
static char *cistrstr(const char *s, const char *sub);
52 54
static void cleanup(void);
53 -
static void drawmenu(void);
55 +
static void drawmenuh(void);
56 +
static void drawmenuv(void);
54 57
static void drawtext(const char *text, unsigned long col[ColLast]);
55 58
static void eprint(const char *errstr, ...);
56 59
static unsigned long getcolor(const char *colstr);
73 76
static int cmdw = 0;
74 77
static int promptw = 0;
75 78
static int ret = 0;
79 +
static int cursor = 0;
76 80
static int screen;
77 81
static unsigned int mw, mh;
78 82
static unsigned int numlockmask = 0;
88 92
static Window root, win;
89 93
static int (*fstrncmp)(const char *, const char *, size_t n) = strncmp;
90 94
static char *(*fstrstr)(const char *, const char *) = strstr;
95 +
static Bool vlist = False;
96 +
static unsigned int lines = 5;
97 +
static void (*calcoffsets)(void) = calcoffsetsh;
98 +
static void (*drawmenu)(void) = drawmenuh;
91 99
92 100
void
93 101
appenditem(Item *i, Item **list, Item **last) {
101 109
}
102 110
103 111
void
104 -
calcoffsets(void) {
112 +
calcoffsetsh(void) {
105 113
	int tw;
106 114
	unsigned int w;
107 115
127 135
	}
128 136
}
129 137
138 +
void
139 +
calcoffsetsv(void) {
140 +
	static unsigned int w;
141 +
142 +
	if(!curr)
143 +
		return;
144 +
	w = (dc.font.height + 2) * (lines + 1);
145 +
	for(next = curr; next; next=next->right) {
146 +
		w -= dc.font.height + 2;
147 +
		if(w <= 0)
148 +
			break;
149 +
	}
150 +
	w = (dc.font.height + 2) * (lines + 1);
151 +
	for(prev = curr; prev && prev->left; prev=prev->left) {
152 +
		w -= dc.font.height + 2;
153 +
		if(w <= 0)
154 +
			break;
155 +
	}
156 +
}
157 +
130 158
char *
131 159
cistrstr(const char *s, const char *sub) {
132 160
	int c, csub;
171 199
}
172 200
173 201
void
174 -
drawmenu(void) {
202 +
drawcursor(void) {
203 +
	XRectangle r = { dc.x, dc.y + 2, 1, dc.h - 4 };
204 +
205 +
	r.x += textnw(text, cursor) + dc.font.height / 2;
206 +
207 +
	XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
208 +
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
209 +
}
210 +
211 +
void
212 +
drawmenuh(void) {
175 213
	Item *i;
176 214
177 215
	dc.x = 0;
190 228
	if(cmdw && item)
191 229
		dc.w = cmdw;
192 230
	drawtext(text[0] ? text : NULL, dc.norm);
231 +
	drawcursor();
193 232
	dc.x += cmdw;
194 233
	if(curr) {
195 234
		dc.w = spaceitem;
212 251
}
213 252
214 253
void
254 +
drawmenuv(void) {
255 +
	Item *i;
256 +
257 +
	dc.x = 0;
258 +
	dc.y = 0;
259 +
	dc.w = mw;
260 +
	dc.h = mh;
261 +
	drawtext(NULL, dc.norm);
262 +
	/* print prompt? */
263 +
	if(promptw) {
264 +
		dc.w = promptw;
265 +
		drawtext(prompt, dc.sel);
266 +
	}
267 +
	dc.x += promptw;
268 +
	dc.w = mw - promptw;
269 +
	/* print command */
270 +
	drawtext(text[0] ? text : NULL, dc.norm);
271 +
	if(curr) {
272 +
		dc.x = 0;
273 +
		dc.w = mw;
274 +
		dc.y += dc.font.height + 2;
275 +
		/* determine maximum items */
276 +
		for(i = curr; i != next; i=i->right) {
277 +
			drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
278 +
			dc.y += dc.font.height + 2;
279 +
		}
280 +
		drawtext(NULL, dc.norm);
281 +
	}
282 +
	XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
283 +
	XFlush(dpy);
284 +
}
285 +
286 +
void
215 287
drawtext(const char *text, unsigned long col[ColLast]) {
216 288
	char buf[256];
217 289
	int i, x, y, h, len, olen;
222 294
	if(!text)
223 295
		return;
224 296
	olen = strlen(text);
225 -
	h = dc.font.ascent + dc.font.descent;
226 -
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
297 +
	h = dc.font.height;
298 +
	y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent;
227 299
	x = dc.x + (h / 2);
228 300
	/* shorten text if necessary */
229 301
	for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
353 425
			text[0] = 0;
354 426
			match(text);
355 427
			drawmenu();
356 -
			return;
428 +
			break;
357 429
		case XK_w:
358 430
		case XK_W:
359 431
			if(len) {
365 437
				match(text);
366 438
				drawmenu();
367 439
			}
368 -
			return;
440 +
			break;
369 441
		}
370 442
	}
371 443
	if(CLEANMASK(e->state) & Mod1Mask) {
389 461
		case XK_G:
390 462
			ksym = XK_End;
391 463
			break;
464 +
		case XK_p:
465 +
			{
466 +
				FILE *fp;
467 +
				char *c;
468 +
				if(!(fp = (FILE*)popen("sselp", "r")))
469 +
					fprintf(stderr, "dmenu: Could not popen sselp\n");
470 +
				c = fgets(text + len, sizeof(text) - len, fp);
471 +
				pclose(fp);
472 +
				if(c == NULL)
473 +
					return;
474 +
			}
475 +
			len = strlen(text);
476 +
			if(len && text[len-1] == '\n')
477 +
				text[--len] = '\0';
478 +
			match(text);
479 +
			drawmenu();
480 +
			return;
392 481
		}
393 482
	}
394 483
	switch(ksym) {
395 484
	default:
396 485
		if(num && !iscntrl((int) buf[0])) {
397 486
			buf[num] = 0;
398 -
			strncpy(text + len, buf, sizeof text - len);
487 +
			memmove(text + cursor + num, text + cursor, sizeof text - cursor);
488 +
			strncpy(text + cursor, buf, sizeof text - cursor);
489 +
			cursor+=num;
399 490
			match(text);
400 491
		}
401 492
		break;
402 493
	case XK_BackSpace:
403 -
		if(len) {
404 -
			text[--len] = 0;
494 +
		if(cursor > 0) {
495 +
			memmove(text + cursor + -1, text + cursor, sizeof text - cursor);
496 +
			cursor--;
405 497
			match(text);
406 498
		}
407 499
		break;
426 518
		calcoffsets();
427 519
		break;
428 520
	case XK_Left:
429 -
		if(!(sel && sel->left))
521 +
	case XK_Up:
522 +
		if(sel && sel->left){
523 +
			sel=sel->left;
524 +
			if(sel->right == curr) {
525 +
				curr = prev;
526 +
				calcoffsets();
527 +
			}
528 +
		}
529 +
		else if(cursor > 0)
530 +
			cursor--;
531 +
		else
430 532
			return;
431 -
		sel=sel->left;
432 -
		if(sel->right == curr) {
433 -
			curr = prev;
434 -
			calcoffsets();
435 -
		}
436 533
		break;
437 534
	case XK_Next:
438 535
		if(!next)
457 554
		running = False;
458 555
		break;
459 556
	case XK_Right:
460 -
		if(!(sel && sel->right))
461 -
			return;
462 -
		sel=sel->right;
463 -
		if(sel == next) {
464 -
			curr = next;
465 -
			calcoffsets();
557 +
	case XK_Down:
558 +
		if(cursor < len)
559 +
			cursor++;
560 +
		else if(sel && sel->right) {
561 +
			sel=sel->right;
562 +
			if(sel == next) {
563 +
				curr = next;
564 +
				calcoffsets();
565 +
			}
466 566
		}
567 +
		else
568 +
			return;
467 569
		break;
468 570
	case XK_Tab:
469 571
		if(!sel)
470 572
			return;
471 573
		strncpy(text, sel->text, sizeof text);
574 +
		cursor = strlen(text);
472 575
		match(text);
473 576
		break;
474 577
	}
578 +
	len = strlen(text);
579 +
	cursor = MIN(cursor, len);
580 +
	cursor = MAX(cursor, 0);
475 581
	drawmenu();
476 582
}
477 583
598 704
599 705
	/* menu window geometry */
600 706
	mh = dc.font.height + 2;
707 +
	mh = vlist ? mh * (lines+1) : mh;
601 708
#if XINERAMA
602 709
	if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
603 710
		i = 0;
676 783
		}
677 784
		else if(!strcmp(argv[i], "-b"))
678 785
			topbar = False;
786 +
		else if(!strcmp(argv[i], "-l")) {
787 +
			vlist = True;
788 +
			calcoffsets = calcoffsetsv;
789 +
			drawmenu = drawmenuv;
790 +
			if(++i < argc) lines += atoi(argv[i]);
791 +
		}
679 792
		else if(!strcmp(argv[i], "-fn")) {
680 793
			if(++i < argc) font = argv[i];
681 794
		}
695 808
			if(++i < argc) selfgcolor = argv[i];
696 809
		}
697 810
		else if(!strcmp(argv[i], "-v"))
698 -
			eprint("dmenu-"VERSION", © 2006-2008 dmenu engineers, see LICENSE for details\n");
811 +
			eprint("dmenu-"VERSION", © 2006-2009 dmenu engineers, see LICENSE for details\n");
699 812
		else
700 -
			eprint("usage: dmenu [-i] [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
813 +
			eprint("usage: dmenu [-i] [-b] [-l <lines>] [-fn <font>] [-nb <color>] [-nf <color>]\n"
701 814
			       "             [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
702 815
	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
703 816
		fprintf(stderr, "warning: no locale support\n");