reorganized d094ebea
Anselm R. Garbe · 2007-09-17 20:53 1 file(s) · +298 −287
dmenu.c +298 −287
40 40
};
41 41
42 42
/* forward declarations */
43 -
static void *emalloc(unsigned int size);
44 -
static void eprint(const char *errstr, ...);
45 -
static char *estrdup(const char *str);
46 -
static void drawtext(const char *text, unsigned long col[ColLast]);
47 -
static unsigned int textw(const char *text);
48 -
static unsigned int textnw(const char *text, unsigned int len);
49 -
static void calcoffsets(void);
50 -
static void drawmenu(void);
51 -
static Bool grabkeyboard(void);
52 -
static unsigned long getcolor(const char *colstr);
53 -
static void initfont(const char *fontstr);
54 -
static int strido(const char *text, const char *pattern);
55 -
static void match(char *pattern);
56 -
static void kpress(XKeyEvent * e);
57 -
static char *readstdin(void);
58 -
static void usage(void);
43 +
void calcoffsets(void);
44 +
void cleanup(void);
45 +
void drawmenu(void);
46 +
void drawtext(const char *text, unsigned long col[ColLast]);
47 +
void *emalloc(unsigned int size);
48 +
void eprint(const char *errstr, ...);
49 +
char *estrdup(const char *str);
50 +
unsigned long getcolor(const char *colstr);
51 +
Bool grabkeyboard(void);
52 +
void initfont(const char *fontstr);
53 +
void kpress(XKeyEvent * e);
54 +
void match(char *pattern);
55 +
void readstdin(void);
56 +
void run(void);
57 +
void setup(Bool bottom);
58 +
int strido(const char *text, const char *pattern);
59 +
unsigned int textnw(const char *text, unsigned int len);
60 +
unsigned int textw(const char *text);
59 61
62 +
#include "config.h"
60 63
61 64
/* variables */
62 -
static int screen;
63 -
static Display *dpy;
64 -
static DC dc = {0};
65 -
static char text[4096];
66 -
static char *prompt = NULL;
67 -
static int mw, mh;
68 -
static int ret = 0;
69 -
static int nitem = 0;
70 -
static unsigned int cmdw = 0;
71 -
static unsigned int promptw = 0;
72 -
static unsigned int numlockmask = 0;
73 -
static Bool running = True;
74 -
static Item *allitems = NULL;	/* first of all items */
75 -
static Item *item = NULL;	/* first of pattern matching items */
76 -
static Item *sel = NULL;
77 -
static Item *next = NULL;
78 -
static Item *prev = NULL;
79 -
static Item *curr = NULL;
80 -
static Window root;
81 -
static Window win;
65 +
char *font = FONT;
66 +
char *maxname = NULL;
67 +
char *normbg = NORMBGCOLOR;
68 +
char *normfg = NORMFGCOLOR;
69 +
char *prompt = NULL;
70 +
char *selbg = SELBGCOLOR;
71 +
char *selfg = SELFGCOLOR;
72 +
char text[4096];
73 +
int screen;
74 +
int ret = 0;
75 +
unsigned int cmdw = 0;
76 +
unsigned int mw, mh;
77 +
unsigned int promptw = 0;
78 +
unsigned int nitem = 0;
79 +
unsigned int numlockmask = 0;
80 +
Bool running = True;
81 +
Display *dpy;
82 +
DC dc = {0};
83 +
Item *allitems = NULL;	/* first of all items */
84 +
Item *item = NULL;	/* first of pattern matching items */
85 +
Item *sel = NULL;
86 +
Item *next = NULL;
87 +
Item *prev = NULL;
88 +
Item *curr = NULL;
89 +
Window root, win;
82 90
83 -
#include "config.h"
84 -
85 -
static void *
86 -
emalloc(unsigned int size) {
87 -
	void *res = malloc(size);
88 -
89 -
	if(!res)
90 -
		eprint("fatal: could not malloc() %u bytes\n", size);
91 -
	return res;
92 -
}
93 -
94 -
static void
95 -
eprint(const char *errstr, ...) {
96 -
	va_list ap;
97 -
98 -
	va_start(ap, errstr);
99 -
	vfprintf(stderr, errstr, ap);
100 -
	va_end(ap);
101 -
	exit(EXIT_FAILURE);
102 -
}
103 -
104 -
static char *
105 -
estrdup(const char *str) {
106 -
	void *res = strdup(str);
107 -
108 -
	if(!res)
109 -
		eprint("fatal: could not malloc() %u bytes\n", strlen(str));
110 -
	return res;
111 -
}
112 -
113 -
114 -
static void
115 -
drawtext(const char *text, unsigned long col[ColLast]) {
116 -
	int x, y, w, h;
117 -
	static char buf[256];
118 -
	unsigned int len, olen;
119 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
120 -
121 -
	XSetForeground(dpy, dc.gc, col[ColBG]);
122 -
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
123 -
	if(!text)
124 -
		return;
125 -
	w = 0;
126 -
	olen = len = strlen(text);
127 -
	if(len >= sizeof buf)
128 -
		len = sizeof buf - 1;
129 -
	memcpy(buf, text, len);
130 -
	buf[len] = 0;
131 -
	h = dc.font.ascent + dc.font.descent;
132 -
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
133 -
	x = dc.x + (h / 2);
134 -
	/* shorten text if necessary */
135 -
	while(len && (w = textnw(buf, len)) > dc.w - h)
136 -
		buf[--len] = 0;
137 -
	if(len < olen) {
138 -
		if(len > 1)
139 -
			buf[len - 1] = '.';
140 -
		if(len > 2)
141 -
			buf[len - 2] = '.';
142 -
		if(len > 3)
143 -
			buf[len - 3] = '.';
144 -
	}
145 -
	if(w > dc.w)
146 -
		return; /* too long */
147 -
	XSetForeground(dpy, dc.gc, col[ColFG]);
148 -
	if(dc.font.set)
149 -
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
150 -
	else
151 -
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
152 -
}
153 -
154 -
static unsigned int
155 -
textw(const char *text) {
156 -
	return textnw(text, strlen(text)) + dc.font.height;
157 -
}
158 -
159 -
static unsigned int
160 -
textnw(const char *text, unsigned int len) {
161 -
	XRectangle r;
162 -
163 -
	if(dc.font.set) {
164 -
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
165 -
		return r.width;
166 -
	}
167 -
	return XTextWidth(dc.font.xfont, text, len);
168 -
}
169 -
170 -
static void
91 +
void
171 92
calcoffsets(void) {
172 93
	unsigned int tw, w;
173 94
193 114
	}
194 115
}
195 116
196 -
static void
117 +
void
118 +
cleanup(void) {
119 +
	Item *itm;
120 +
121 +
	while(allitems) {
122 +
		itm = allitems->next;
123 +
		free(allitems->text);
124 +
		free(allitems);
125 +
		allitems = itm;
126 +
	}
127 +
	if(dc.font.set)
128 +
		XFreeFontSet(dpy, dc.font.set);
129 +
	else
130 +
		XFreeFont(dpy, dc.font.xfont);
131 +
	XFreePixmap(dpy, dc.drawable);
132 +
	XFreeGC(dpy, dc.gc);
133 +
	XDestroyWindow(dpy, win);
134 +
	XUngrabKeyboard(dpy, CurrentTime);
135 +
}
136 +
137 +
void
197 138
drawmenu(void) {
198 139
	Item *i;
199 140
234 175
	XFlush(dpy);
235 176
}
236 177
237 -
static Bool
238 -
grabkeyboard(void) {
239 -
	unsigned int len;
178 +
void
179 +
drawtext(const char *text, unsigned long col[ColLast]) {
180 +
	int x, y, w, h;
181 +
	static char buf[256];
182 +
	unsigned int len, olen;
183 +
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
240 184
241 -
	for(len = 1000; len; len--) {
242 -
		if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
243 -
			== GrabSuccess)
244 -
			break;
245 -
		usleep(1000);
185 +
	XSetForeground(dpy, dc.gc, col[ColBG]);
186 +
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
187 +
	if(!text)
188 +
		return;
189 +
	w = 0;
190 +
	olen = len = strlen(text);
191 +
	if(len >= sizeof buf)
192 +
		len = sizeof buf - 1;
193 +
	memcpy(buf, text, len);
194 +
	buf[len] = 0;
195 +
	h = dc.font.ascent + dc.font.descent;
196 +
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
197 +
	x = dc.x + (h / 2);
198 +
	/* shorten text if necessary */
199 +
	while(len && (w = textnw(buf, len)) > dc.w - h)
200 +
		buf[--len] = 0;
201 +
	if(len < olen) {
202 +
		if(len > 1)
203 +
			buf[len - 1] = '.';
204 +
		if(len > 2)
205 +
			buf[len - 2] = '.';
206 +
		if(len > 3)
207 +
			buf[len - 3] = '.';
246 208
	}
247 -
	return len > 0;
209 +
	if(w > dc.w)
210 +
		return; /* too long */
211 +
	XSetForeground(dpy, dc.gc, col[ColFG]);
212 +
	if(dc.font.set)
213 +
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
214 +
	else
215 +
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
216 +
}
217 +
218 +
void *
219 +
emalloc(unsigned int size) {
220 +
	void *res = malloc(size);
221 +
222 +
	if(!res)
223 +
		eprint("fatal: could not malloc() %u bytes\n", size);
224 +
	return res;
225 +
}
226 +
227 +
void
228 +
eprint(const char *errstr, ...) {
229 +
	va_list ap;
230 +
231 +
	va_start(ap, errstr);
232 +
	vfprintf(stderr, errstr, ap);
233 +
	va_end(ap);
234 +
	exit(EXIT_FAILURE);
235 +
}
236 +
237 +
char *
238 +
estrdup(const char *str) {
239 +
	void *res = strdup(str);
240 +
241 +
	if(!res)
242 +
		eprint("fatal: could not malloc() %u bytes\n", strlen(str));
243 +
	return res;
248 244
}
249 245
250 -
static unsigned long
246 +
unsigned long
251 247
getcolor(const char *colstr) {
252 248
	Colormap cmap = DefaultColormap(dpy, screen);
253 249
	XColor color;
257 253
	return color.pixel;
258 254
}
259 255
260 -
static void
256 +
Bool
257 +
grabkeyboard(void) {
258 +
	unsigned int len;
259 +
260 +
	for(len = 1000; len; len--) {
261 +
		if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
262 +
			== GrabSuccess)
263 +
			break;
264 +
		usleep(1000);
265 +
	}
266 +
	return len > 0;
267 +
}
268 +
269 +
void
261 270
initfont(const char *fontstr) {
262 271
	char *def, **missing;
263 272
	int i, n;
299 308
	dc.font.height = dc.font.ascent + dc.font.descent;
300 309
}
301 310
302 -
static int
303 -
strido(const char *text, const char *pattern) {
304 -
	for(; *text && *pattern; text++)
305 -
		if (*text == *pattern)
306 -
			pattern++;
307 -
	return !*pattern;
308 -
}                                  
309 -
310 -
static void
311 -
match(char *pattern) {
312 -
	unsigned int plen;
313 -
	Item *i, *j;
314 -
315 -
	if(!pattern)
316 -
		return;
317 -
	plen = strlen(pattern);
318 -
	item = j = NULL;
319 -
	nitem = 0;
320 -
	for(i = allitems; i; i=i->next)
321 -
		if(!plen || !strncmp(pattern, i->text, plen)) {
322 -
			if(!j)
323 -
				item = i;
324 -
			else
325 -
				j->right = i;
326 -
			i->left = j;
327 -
			i->right = NULL;
328 -
			j = i;
329 -
			nitem++;
330 -
		}
331 -
	for(i = allitems; i; i=i->next)
332 -
		if(plen && strncmp(pattern, i->text, plen)
333 -
				&& strstr(i->text, pattern)) {
334 -
			if(!j)                               
335 -
				item = i;                              
336 -
			else                                     
337 -
				j->right = i;                          
338 -
			i->left = j;      
339 -
			i->right = NULL;                         
340 -
			j = i;                                      
341 -
			nitem++;                                       
342 -
		}                                              
343 -
	for(i = allitems; i; i=i->next)                            
344 -
		if(plen && strncmp(pattern, i->text, plen)             
345 -
				&& !strstr(i->text, pattern)          
346 -
				&& strido(i->text,pattern)) { 
347 -
			if(!j)
348 -
				item = i;
349 -
			else
350 -
				j->right = i;
351 -
			i->left = j;
352 -
			i->right = NULL;
353 -
			j = i;
354 -
			nitem++;
355 -
		}
356 -
	curr = prev = next = sel = item;
357 -
	calcoffsets();
358 -
}
359 -
360 -
static void
311 +
void
361 312
kpress(XKeyEvent * e) {
362 313
	char buf[32];
363 314
	int i, num;
528 479
	drawmenu();
529 480
}
530 481
531 -
static char *
482 +
void
483 +
match(char *pattern) {
484 +
	unsigned int plen;
485 +
	Item *i, *j;
486 +
487 +
	if(!pattern)
488 +
		return;
489 +
	plen = strlen(pattern);
490 +
	item = j = NULL;
491 +
	nitem = 0;
492 +
	for(i = allitems; i; i=i->next)
493 +
		if(!plen || !strncmp(pattern, i->text, plen)) {
494 +
			if(!j)
495 +
				item = i;
496 +
			else
497 +
				j->right = i;
498 +
			i->left = j;
499 +
			i->right = NULL;
500 +
			j = i;
501 +
			nitem++;
502 +
		}
503 +
	for(i = allitems; i; i=i->next)
504 +
		if(plen && strncmp(pattern, i->text, plen)
505 +
				&& strstr(i->text, pattern)) {
506 +
			if(!j)                               
507 +
				item = i;                              
508 +
			else                                     
509 +
				j->right = i;                          
510 +
			i->left = j;      
511 +
			i->right = NULL;                         
512 +
			j = i;                                      
513 +
			nitem++;                                       
514 +
		}                                              
515 +
	for(i = allitems; i; i=i->next)                            
516 +
		if(plen && strncmp(pattern, i->text, plen)             
517 +
				&& !strstr(i->text, pattern)          
518 +
				&& strido(i->text,pattern)) { 
519 +
			if(!j)
520 +
				item = i;
521 +
			else
522 +
				j->right = i;
523 +
			i->left = j;
524 +
			i->right = NULL;
525 +
			j = i;
526 +
			nitem++;
527 +
		}
528 +
	curr = prev = next = sel = item;
529 +
	calcoffsets();
530 +
}
531 +
532 +
void
532 533
readstdin(void) {
533 -
	static char *maxname = NULL;
534 534
	char *p, buf[1024];
535 535
	unsigned int len = 0, max = 0;
536 536
	Item *i, *new;
554 554
			i->next = new;
555 555
		i = new;
556 556
	}
557 +
}
557 558
558 -
	return maxname;
559 -
}
559 +
void
560 +
run(void) {
561 +
	XEvent ev;
560 562
561 -
static void
562 -
usage(void) {
563 -
	eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
564 -
		"             [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
563 +
	/* main event loop */
564 +
	while(running && !XNextEvent(dpy, &ev))
565 +
		switch (ev.type) {
566 +
		default:	/* ignore all crap */
567 +
			break;
568 +
		case KeyPress:
569 +
			kpress(&ev.xkey);
570 +
			break;
571 +
		case Expose:
572 +
			if(ev.xexpose.count == 0)
573 +
				drawmenu();
574 +
			break;
575 +
		}
565 576
}
566 577
567 -
int
568 -
main(int argc, char *argv[]) {
569 -
	Bool bottom = False;
570 -
	char *font = FONT;
571 -
	char *maxname;
572 -
	char *normbg = NORMBGCOLOR;
573 -
	char *normfg = NORMFGCOLOR;
574 -
	char *selbg = SELBGCOLOR;
575 -
	char *selfg = SELFGCOLOR;
576 -
	int i, j;
577 -
	Item *itm;
578 -
	XEvent ev;
578 +
void
579 +
setup(Bool bottom) {
580 +
	unsigned int i, j;
579 581
	XModifierKeymap *modmap;
580 582
	XSetWindowAttributes wa;
581 583
582 -
	/* command line args */
583 -
	for(i = 1; i < argc; i++)
584 -
		if(!strcmp(argv[i], "-b")) {
585 -
			bottom = True;
586 -
		}
587 -
		else if(!strcmp(argv[i], "-fn")) {
588 -
			if(++i < argc) font = argv[i];
589 -
		}
590 -
		else if(!strcmp(argv[i], "-nb")) {
591 -
			if(++i < argc) normbg = argv[i];
592 -
		}
593 -
		else if(!strcmp(argv[i], "-nf")) {
594 -
			if(++i < argc) normfg = argv[i];
595 -
		}
596 -
		else if(!strcmp(argv[i], "-p")) {
597 -
			if(++i < argc) prompt = argv[i];
598 -
		}
599 -
		else if(!strcmp(argv[i], "-sb")) {
600 -
			if(++i < argc) selbg = argv[i];
601 -
		}
602 -
		else if(!strcmp(argv[i], "-sf")) {
603 -
			if(++i < argc) selfg = argv[i];
604 -
		}
605 -
		else if(!strcmp(argv[i], "-v"))
606 -
			eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n");
607 -
		else
608 -
			usage();
609 -
	setlocale(LC_CTYPE, "");
610 -
	dpy = XOpenDisplay(0);
611 -
	if(!dpy)
612 -
		eprint("dmenu: cannot open display\n");
613 -
	screen = DefaultScreen(dpy);
614 -
	root = RootWindow(dpy, screen);
615 -
	if(isatty(STDIN_FILENO)) {
616 -
		maxname = readstdin();
617 -
		running = grabkeyboard();
618 -
	}
619 -
	else { /* prevent keypress loss */
620 -
		running = grabkeyboard();
621 -
		maxname = readstdin();
622 -
	}
623 584
	/* init modifier map */
624 585
	modmap = XGetModifierMapping(dpy);
625 -
	for (i = 0; i < 8; i++) {
626 -
		for (j = 0; j < modmap->max_keypermod; j++) {
586 +
	for(i = 0; i < 8; i++)
587 +
		for(j = 0; j < modmap->max_keypermod; j++) {
627 588
			if(modmap->modifiermap[i * modmap->max_keypermod + j]
628 589
			== XKeysymToKeycode(dpy, XK_Num_Lock))
629 590
				numlockmask = (1 << i);
630 591
		}
631 -
	}
632 592
	XFreeModifiermap(modmap);
593 +
633 594
	/* style */
634 595
	dc.norm[ColBG] = getcolor(normbg);
635 596
	dc.norm[ColFG] = getcolor(normfg);
636 597
	dc.sel[ColBG] = getcolor(selbg);
637 598
	dc.sel[ColFG] = getcolor(selfg);
638 599
	initfont(font);
600 +
639 601
	/* menu window */
640 602
	wa.override_redirect = 1;
641 603
	wa.background_pixmap = ParentRelative;
647 609
			DefaultDepth(dpy, screen), CopyFromParent,
648 610
			DefaultVisual(dpy, screen),
649 611
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
612 +
650 613
	/* pixmap */
651 614
	dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen));
652 615
	dc.gc = XCreateGC(dpy, root, 0, 0);
664 627
	text[0] = 0;
665 628
	match(text);
666 629
	XMapRaised(dpy, win);
667 -
	drawmenu();
668 -
	XSync(dpy, False);
630 +
}
669 631
670 -
	/* main event loop */
671 -
	while(running && !XNextEvent(dpy, &ev))
672 -
		switch (ev.type) {
673 -
		default:	/* ignore all crap */
674 -
			break;
675 -
		case KeyPress:
676 -
			kpress(&ev.xkey);
677 -
			break;
678 -
		case Expose:
679 -
			if(ev.xexpose.count == 0)
680 -
				drawmenu();
681 -
			break;
632 +
int
633 +
strido(const char *text, const char *pattern) {
634 +
	for(; *text && *pattern; text++)
635 +
		if (*text == *pattern)
636 +
			pattern++;
637 +
	return !*pattern;
638 +
}                                  
639 +
640 +
unsigned int
641 +
textnw(const char *text, unsigned int len) {
642 +
	XRectangle r;
643 +
644 +
	if(dc.font.set) {
645 +
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
646 +
		return r.width;
647 +
	}
648 +
	return XTextWidth(dc.font.xfont, text, len);
649 +
}
650 +
651 +
unsigned int
652 +
textw(const char *text) {
653 +
	return textnw(text, strlen(text)) + dc.font.height;
654 +
}
655 +
656 +
int
657 +
main(int argc, char *argv[]) {
658 +
	Bool bottom = False;
659 +
	unsigned int i;
660 +
661 +
	/* command line args */
662 +
	for(i = 1; i < argc; i++)
663 +
		if(!strcmp(argv[i], "-b")) {
664 +
			bottom = True;
682 665
		}
666 +
		else if(!strcmp(argv[i], "-fn")) {
667 +
			if(++i < argc) font = argv[i];
668 +
		}
669 +
		else if(!strcmp(argv[i], "-nb")) {
670 +
			if(++i < argc) normbg = argv[i];
671 +
		}
672 +
		else if(!strcmp(argv[i], "-nf")) {
673 +
			if(++i < argc) normfg = argv[i];
674 +
		}
675 +
		else if(!strcmp(argv[i], "-p")) {
676 +
			if(++i < argc) prompt = argv[i];
677 +
		}
678 +
		else if(!strcmp(argv[i], "-sb")) {
679 +
			if(++i < argc) selbg = argv[i];
680 +
		}
681 +
		else if(!strcmp(argv[i], "-sf")) {
682 +
			if(++i < argc) selfg = argv[i];
683 +
		}
684 +
		else if(!strcmp(argv[i], "-v"))
685 +
			eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n");
686 +
		else
687 +
			eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
688 +
			"             [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
689 +
	setlocale(LC_CTYPE, "");
690 +
	dpy = XOpenDisplay(0);
691 +
	if(!dpy)
692 +
		eprint("dmenu: cannot open display\n");
693 +
	screen = DefaultScreen(dpy);
694 +
	root = RootWindow(dpy, screen);
683 695
684 -
	/* cleanup */
685 -
	while(allitems) {
686 -
		itm = allitems->next;
687 -
		free(allitems->text);
688 -
		free(allitems);
689 -
		allitems = itm;
696 +
	if(isatty(STDIN_FILENO)) {
697 +
		readstdin();
698 +
		running = grabkeyboard();
690 699
	}
691 -
	if(dc.font.set)
692 -
		XFreeFontSet(dpy, dc.font.set);
693 -
	else
694 -
		XFreeFont(dpy, dc.font.xfont);
695 -
	XFreePixmap(dpy, dc.drawable);
696 -
	XFreeGC(dpy, dc.gc);
697 -
	XDestroyWindow(dpy, win);
698 -
	XUngrabKeyboard(dpy, CurrentTime);
700 +
	else { /* prevent keypress loss */
701 +
		running = grabkeyboard();
702 +
		readstdin();
703 +
	}
704 +
705 +
	setup(bottom);
706 +
	drawmenu();
707 +
	XSync(dpy, False);
708 +
	run();
709 +
	cleanup();
699 710
	XCloseDisplay(dpy);
700 711
	return ret;
701 712
}