decoupled draw.c from dmenu & dinput 96c65400
Connor Lane Smith · 2010-06-24 16:18 4 file(s) · +110 −116
dinput.c +22 −18
38 38
static char text[4096];
39 39
static int promptw = 0;
40 40
static int ret = 0;
41 +
static int screen;
41 42
static unsigned int cursor = 0;
42 43
static unsigned int numlockmask = 0;
44 +
static unsigned int mw, mh;
43 45
static Bool running = True;
44 -
static Window win;
45 -
46 -
Display *dpy;
47 -
DC dc;
48 -
int screen;
49 -
unsigned int mw, mh;
50 -
Window parent;
46 +
static DC dc;
47 +
static Display *dpy;
48 +
static Window win, parent;
51 49
52 50
void
53 51
cleanup(void) {
54 -
	drawcleanup();
52 +
	cleanupdraw(&dc);
55 53
	XDestroyWindow(dpy, win);
56 54
	XUngrabKeyboard(dpy, CurrentTime);
57 55
}
60 58
drawcursor(void) {
61 59
	XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 };
62 60
63 -
	r.x += textnw(text, cursor) + dc.font.height / 2;
61 +
	r.x += textnw(&dc, text, cursor) + dc.font.height / 2;
64 62
65 63
	XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
66 64
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
73 71
	dc.y = 0;
74 72
	dc.w = mw;
75 73
	dc.h = mh;
76 -
	drawtext(NULL, dc.norm);
74 +
	drawtext(&dc, NULL, dc.norm);
77 75
	/* print prompt? */
78 76
	if(prompt) {
79 77
		dc.w = promptw;
80 -
		drawtext(prompt, dc.sel);
78 +
		drawtext(&dc, prompt, dc.sel);
81 79
		dc.x += dc.w;
82 80
	}
83 81
	dc.w = mw - dc.x;
84 -
	drawtext(*text ? text : NULL, dc.norm);
82 +
	drawtext(&dc, *text ? text : NULL, dc.norm);
85 83
	drawcursor();
86 84
	XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
87 85
	XFlush(dpy);
269 267
		}
270 268
	XFreeModifiermap(modmap);
271 269
272 -
	initfont(font);
270 +
	dc.dpy = dpy;
271 +
	dc.norm[ColBG] = getcolor(&dc, normbgcolor);
272 +
	dc.norm[ColFG] = getcolor(&dc, normfgcolor);
273 +
	dc.sel[ColBG] = getcolor(&dc, selbgcolor);
274 +
	dc.sel[ColFG] = getcolor(&dc, selfgcolor);
275 +
	initfont(&dc, font);
276 +
	fprintf(stderr, "dc.font.xfont: %u\n", (size_t)dc.font.xfont);
273 277
274 -
	/* menu window */
278 +
	/* input window */
275 279
	wa.override_redirect = True;
276 280
	wa.background_pixmap = ParentRelative;
277 281
	wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | VisibilityChangeMask;
278 282
279 -
	/* menu window geometry */
280 -
	mh = (dc.font.height + 2);
283 +
	/* input window geometry */
284 +
	mh = dc.font.height + 2;
281 285
#if XINERAMA
282 286
	if(parent == RootWindow(dpy, screen) && XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
283 287
		i = 0;
309 313
			DefaultVisual(dpy, screen),
310 314
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
311 315
312 -
	drawsetup();
316 +
	setupdraw(&dc, win);
313 317
	if(prompt)
314 -
		promptw = MIN(textw(prompt), mw / 5);
318 +
		promptw = MIN(textw(&dc, prompt), mw / 5);
315 319
	cursor = strlen(text);
316 320
	XMapRaised(dpy, win);
317 321
}
dmenu.c +26 −23
55 55
static int cmdw = 0;
56 56
static int promptw = 0;
57 57
static int ret = 0;
58 +
static int screen;
58 59
static unsigned int lines = 0;
59 60
static unsigned int numlockmask = 0;
61 +
static unsigned int mw, mh;
60 62
static Bool running = True;
63 +
static DC dc;
64 +
static Display *dpy;
61 65
static Item *allitems = NULL;  /* first of all items */
62 66
static Item *item = NULL;      /* first of pattern matching items */
63 67
static Item *sel = NULL;
64 68
static Item *next = NULL;
65 69
static Item *prev = NULL;
66 70
static Item *curr = NULL;
67 -
static Window win;
71 +
static Window win, parent;
68 72
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
69 73
static char *(*fstrstr)(const char *, const char *) = strstr;
70 74
static void (*calcoffsets)(void) = calcoffsetsh;
71 75
72 -
Display *dpy;
73 -
DC dc;
74 -
int screen;
75 -
unsigned int mw, mh;
76 -
Window parent;
77 -
78 76
void
79 77
appenditem(Item *i, Item **list, Item **last) {
80 78
	if(!(*last))
92 90
93 91
	w = promptw + cmdw + (2 * spaceitem);
94 92
	for(next = curr; next; next = next->right)
95 -
		if((w += MIN(textw(next->text), mw / 3)) > mw)
93 +
		if((w += MIN(textw(&dc, next->text), mw / 3)) > mw)
96 94
			break;
97 95
	w = promptw + cmdw + (2 * spaceitem);
98 96
	for(prev = curr; prev && prev->left; prev = prev->left)
99 -
		if((w += MIN(textw(prev->left->text), mw / 3)) > mw)
97 +
		if((w += MIN(textw(&dc, prev->left->text), mw / 3)) > mw)
100 98
			break;
101 99
}
102 100
143 141
		free(allitems);
144 142
		allitems = itm;
145 143
	}
146 -
	drawcleanup();
144 +
	cleanupdraw(&dc);
147 145
	XDestroyWindow(dpy, win);
148 146
	XUngrabKeyboard(dpy, CurrentTime);
149 147
}
161 159
	dc.y = 0;
162 160
	dc.w = mw;
163 161
	dc.h = mh;
164 -
	drawtext(NULL, dc.norm);
162 +
	drawtext(&dc, NULL, dc.norm);
165 163
	/* print prompt? */
166 164
	if(prompt) {
167 165
		dc.w = promptw;
168 -
		drawtext(prompt, dc.sel);
166 +
		drawtext(&dc, prompt, dc.sel);
169 167
		dc.x += dc.w;
170 168
	}
171 169
	dc.w = mw - dc.x;
172 170
	/* print command */
173 171
	if(cmdw && item && lines == 0)
174 172
		dc.w = cmdw;
175 -
	drawtext(*text ? text : NULL, dc.norm);
173 +
	drawtext(&dc, *text ? text : NULL, dc.norm);
176 174
	if(curr) {
177 175
		if(lines > 0)
178 176
			drawmenuv();
189 187
190 188
	dc.x += cmdw;
191 189
	dc.w = spaceitem;
192 -
	drawtext(curr->left ? "<" : NULL, dc.norm);
190 +
	drawtext(&dc, curr->left ? "<" : NULL, dc.norm);
193 191
	dc.x += dc.w;
194 192
	for(i = curr; i != next; i=i->right) {
195 -
		dc.w = MIN(textw(i->text), mw / 3);
196 -
		drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
193 +
		dc.w = MIN(textw(&dc, i->text), mw / 3);
194 +
		drawtext(&dc, i->text, (sel == i) ? dc.sel : dc.norm);
197 195
		dc.x += dc.w;
198 196
	}
199 197
	dc.w = spaceitem;
200 198
	dc.x = mw - dc.w;
201 -
	drawtext(next ? ">" : NULL, dc.norm);
199 +
	drawtext(&dc, next ? ">" : NULL, dc.norm);
202 200
}
203 201
204 202
void
209 207
	dc.h = dc.font.height + 2;
210 208
	dc.y = dc.h;
211 209
	for(i = curr; i != next; i=i->right) {
212 -
		drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
210 +
		drawtext(&dc, i->text, (sel == i) ? dc.sel : dc.norm);
213 211
		dc.y += dc.h;
214 212
	}
215 213
	dc.h = mh - dc.y;
216 -
	drawtext(NULL, dc.norm);
214 +
	drawtext(&dc, NULL, dc.norm);
217 215
}
218 216
219 217
Bool
491 489
		}
492 490
	XFreeModifiermap(modmap);
493 491
494 -
	initfont(font);
492 +
	dc.dpy = dpy;
493 +
	dc.norm[ColBG] = getcolor(&dc, normbgcolor);
494 +
	dc.norm[ColFG] = getcolor(&dc, normfgcolor);
495 +
	dc.sel[ColBG] = getcolor(&dc, selbgcolor);
496 +
	dc.sel[ColFG] = getcolor(&dc, selfgcolor);
497 +
	initfont(&dc, font);
495 498
496 499
	/* menu window */
497 500
	wa.override_redirect = True;
531 534
			DefaultVisual(dpy, screen),
532 535
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
533 536
534 -
	drawsetup();
537 +
	setupdraw(&dc, win);
535 538
	if(maxname)
536 -
		cmdw = MIN(textw(maxname), mw / 3);
539 +
		cmdw = MIN(textw(&dc, maxname), mw / 3);
537 540
	if(prompt)
538 -
		promptw = MIN(textw(prompt), mw / 5);
541 +
		promptw = MIN(textw(&dc, prompt), mw / 5);
539 542
	text[0] = '\0';
540 543
	match(text);
541 544
	XMapRaised(dpy, win);
draw.c +52 −55
14 14
#define MAX(a, b)               ((a) > (b) ? (a) : (b))
15 15
16 16
/* variables */
17 -
char *progname;
17 +
const char *progname;
18 18
19 19
void
20 -
drawcleanup(void) {
21 -
	if(dc.font.set)
22 -
		XFreeFontSet(dpy, dc.font.set);
20 +
cleanupdraw(DC *dc) {
21 +
	if(dc->font.set)
22 +
		XFreeFontSet(dc->dpy, dc->font.set);
23 23
	else
24 -
		XFreeFont(dpy, dc.font.xfont);
25 -
	XFreePixmap(dpy, dc.drawable);
26 -
	XFreeGC(dpy, dc.gc);
24 +
		XFreeFont(dc->dpy, dc->font.xfont);
25 +
	XFreePixmap(dc->dpy, dc->drawable);
26 +
	XFreeGC(dc->dpy, dc->gc);
27 27
}
28 28
29 29
void
30 -
drawsetup(void) {
31 -
	/* style */
32 -
	dc.norm[ColBG] = getcolor(normbgcolor);
33 -
	dc.norm[ColFG] = getcolor(normfgcolor);
34 -
	dc.sel[ColBG] = getcolor(selbgcolor);
35 -
	dc.sel[ColFG] = getcolor(selfgcolor);
30 +
setupdraw(DC *dc, Window w) {
31 +
	XWindowAttributes wa;
36 32
37 -
	/* pixmap */
38 -
	dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, screen));
39 -
	dc.gc = XCreateGC(dpy, parent, 0, NULL);
40 -
	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
41 -
	if(!dc.font.set)
42 -
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
33 +
	XGetWindowAttributes(dc->dpy, w, &wa);
34 +
	dc->drawable = XCreatePixmap(dc->dpy, w, wa.width, wa.height,
35 +
		DefaultDepth(dc->dpy, DefaultScreen(dc->dpy)));
36 +
	dc->gc = XCreateGC(dc->dpy, w, 0, NULL);
37 +
	XSetLineAttributes(dc->dpy, dc->gc, 1, LineSolid, CapButt, JoinMiter);
38 +
	if(!dc->font.set)
39 +
		XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid);
43 40
}
44 41
45 42
void
46 -
drawtext(const char *text, unsigned long col[ColLast]) {
43 +
drawtext(DC *dc, const char *text, unsigned long col[ColLast]) {
47 44
	char buf[256];
48 45
	int i, x, y, h, len, olen;
49 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
46 +
	XRectangle r = { dc->x, dc->y, dc->w, dc->h };
50 47
51 -
	XSetForeground(dpy, dc.gc, col[ColBG]);
52 -
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
48 +
	XSetForeground(dc->dpy, dc->gc, col[ColBG]);
49 +
	XFillRectangles(dc->dpy, dc->drawable, dc->gc, &r, 1);
53 50
	if(!text)
54 51
		return;
55 52
	olen = strlen(text);
56 -
	h = dc.font.height;
57 -
	y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent;
58 -
	x = dc.x + (h / 2);
53 +
	h = dc->font.height;
54 +
	y = dc->y + ((h+2) / 2) - (h / 2) + dc->font.ascent;
55 +
	x = dc->x + (h / 2);
59 56
	/* shorten text if necessary */
60 -
	for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
57 +
	for(len = MIN(olen, sizeof buf); len && textnw(dc, text, len) > dc->w - h; len--);
61 58
	if(!len)
62 59
		return;
63 60
	memcpy(buf, text, len);
64 61
	if(len < olen)
65 62
		for(i = len; i && i > len - 3; buf[--i] = '.');
66 -
	XSetForeground(dpy, dc.gc, col[ColFG]);
67 -
	if(dc.font.set)
68 -
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
63 +
	XSetForeground(dc->dpy, dc->gc, col[ColFG]);
64 +
	if(dc->font.set)
65 +
		XmbDrawString(dc->dpy, dc->drawable, dc->font.set, dc->gc, x, y, buf, len);
69 66
	else
70 -
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
67 +
		XDrawString(dc->dpy, dc->drawable, dc->gc, x, y, buf, len);
71 68
}
72 69
73 70
void
74 -
eprint(const char *errstr, ...) {
71 +
eprint(const char *fmt, ...) {
75 72
	va_list ap;
76 73
77 74
	fprintf(stderr, "%s: ", progname);
78 -
	va_start(ap, errstr);
79 -
	vfprintf(stderr, errstr, ap);
75 +
	va_start(ap, fmt);
76 +
	vfprintf(stderr, fmt, ap);
80 77
	va_end(ap);
81 78
	exit(EXIT_FAILURE);
82 79
}
83 80
84 81
unsigned long
85 -
getcolor(const char *colstr) {
86 -
	Colormap cmap = DefaultColormap(dpy, screen);
82 +
getcolor(DC *dc, const char *colstr) {
83 +
	Colormap cmap = DefaultColormap(dc->dpy, DefaultScreen(dc->dpy));
87 84
	XColor color;
88 85
89 -
	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
86 +
	if(!XAllocNamedColor(dc->dpy, cmap, colstr, &color, &color))
90 87
		eprint("cannot allocate color '%s'\n", colstr);
91 88
	return color.pixel;
92 89
}
93 90
94 91
void
95 -
initfont(const char *fontstr) {
92 +
initfont(DC *dc, const char *fontstr) {
96 93
	char *def, **missing = NULL;
97 94
	int i, n;
98 95
99 96
	if(!fontstr || !*fontstr)
100 97
		eprint("cannot load null font\n");
101 -
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
98 +
	dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def);
102 99
	if(missing)
103 100
		XFreeStringList(missing);
104 -
	if(dc.font.set) {
101 +
	if(dc->font.set) {
105 102
		XFontStruct **xfonts;
106 103
		char **font_names;
107 -
		dc.font.ascent = dc.font.descent = 0;
108 -
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
104 +
		dc->font.ascent = dc->font.descent = 0;
105 +
		n = XFontsOfFontSet(dc->font.set, &xfonts, &font_names);
109 106
		for(i = 0; i < n; i++) {
110 -
			dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
111 -
			dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent);
107 +
			dc->font.ascent = MAX(dc->font.ascent, (*xfonts)->ascent);
108 +
			dc->font.descent = MAX(dc->font.descent, (*xfonts)->descent);
112 109
			xfonts++;
113 110
		}
114 111
	}
115 112
	else {
116 -
		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
117 -
		&& !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
113 +
		if(!(dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))
114 +
		&& !(dc->font.xfont = XLoadQueryFont(dc->dpy, "fixed")))
118 115
			eprint("cannot load font '%s'\n", fontstr);
119 -
		dc.font.ascent = dc.font.xfont->ascent;
120 -
		dc.font.descent = dc.font.xfont->descent;
116 +
		dc->font.ascent = dc->font.xfont->ascent;
117 +
		dc->font.descent = dc->font.xfont->descent;
121 118
	}
122 -
	dc.font.height = dc.font.ascent + dc.font.descent;
119 +
	dc->font.height = dc->font.ascent + dc->font.descent;
123 120
}
124 121
125 122
int
126 -
textnw(const char *text, unsigned int len) {
123 +
textnw(DC *dc, const char *text, unsigned int len) {
127 124
	XRectangle r;
128 125
129 -
	if(dc.font.set) {
130 -
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
126 +
	if(dc->font.set) {
127 +
		XmbTextExtents(dc->font.set, text, len, NULL, &r);
131 128
		return r.width;
132 129
	}
133 -
	return XTextWidth(dc.font.xfont, text, len);
130 +
	return XTextWidth(dc->font.xfont, text, len);
134 131
}
135 132
136 133
int
137 -
textw(const char *text) {
138 -
	return textnw(text, strlen(text)) + dc.font.height;
134 +
textw(DC *dc, const char *text) {
135 +
	return textnw(dc, text, strlen(text)) + dc->font.height;
139 136
}
draw.h +10 −20
9 9
	unsigned long norm[ColLast];
10 10
	unsigned long sel[ColLast];
11 11
	Drawable drawable;
12 +
	Display *dpy;
12 13
	GC gc;
13 14
	struct {
14 15
		XFontStruct *xfont;
20 21
} DC; /* draw context */
21 22
22 23
/* forward declarations */
23 -
void drawcleanup(void);
24 -
void drawsetup(void);
25 -
void drawtext(const char *text, unsigned long col[ColLast]);
26 -
void eprint(const char *errstr, ...);
27 -
unsigned long getcolor(const char *colstr);
28 -
void initfont(const char *fontstr);
29 -
int textnw(const char *text, unsigned int len);
30 -
int textw(const char *text);
24 +
void cleanupdraw(DC *dc);
25 +
void setupdraw(DC *dc, Window w);
26 +
void drawtext(DC *dc, const char *text, unsigned long col[ColLast]);
27 +
void eprint(const char *fmt, ...);
28 +
unsigned long getcolor(DC *dc, const char *colstr);
29 +
void initfont(DC *dc, const char *fontstr);
30 +
int textnw(DC *dc, const char *text, unsigned int len);
31 +
int textw(DC *dc, const char *text);
31 32
32 33
/* variables */
33 -
extern char *progname;
34 -
extern Display *dpy;
35 -
extern DC dc;
36 -
extern int screen;
37 -
extern unsigned int mw, mh;
38 -
extern Window parent;
39 -
40 -
extern const char *font;
41 -
extern const char *normbgcolor;
42 -
extern const char *normfgcolor;
43 -
extern const char *selbgcolor;
44 -
extern const char *selfgcolor;
34 +
extern const char *progname;