all repos — dwm @ 7e476fb86ba254e6fe3a916ed7b5298e432a469c

fork of suckless dynamic window manager

bar.c (view raw)

  1/* See LICENSE file for copyright and license details. */
  2#include "dwm.h"
  3#include <string.h>
  4#include <stdio.h>
  5
  6/* static */
  7
  8static void
  9drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
 10	int x;
 11	XGCValues gcv;
 12	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
 13
 14	gcv.foreground = col[ColFG];
 15	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
 16	x = (dc.font.ascent + dc.font.descent + 2) / 4;
 17	r.x = dc.x + 1;
 18	r.y = dc.y + 1;
 19	if(filled) {
 20		r.width = r.height = x + 1;
 21		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 22	}
 23	else if(empty) {
 24		r.width = r.height = x;
 25		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 26	}
 27}
 28
 29static unsigned long
 30initcolor(const char *colstr) {
 31	Colormap cmap = DefaultColormap(dpy, screen);
 32	XColor color;
 33
 34	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 35		eprint("error, cannot allocate color '%s'\n", colstr);
 36	return color.pixel;
 37}
 38
 39static void
 40initfont(const char *fontstr) {
 41	char *def, **missing;
 42	int i, n;
 43
 44	missing = NULL;
 45	if(dc.font.set)
 46		XFreeFontSet(dpy, dc.font.set);
 47	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 48	if(missing) {
 49		while(n--)
 50			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
 51		XFreeStringList(missing);
 52	}
 53	if(dc.font.set) {
 54		XFontSetExtents *font_extents;
 55		XFontStruct **xfonts;
 56		char **font_names;
 57		dc.font.ascent = dc.font.descent = 0;
 58		font_extents = XExtentsOfFontSet(dc.font.set);
 59		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
 60		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
 61			if(dc.font.ascent < (*xfonts)->ascent)
 62				dc.font.ascent = (*xfonts)->ascent;
 63			if(dc.font.descent < (*xfonts)->descent)
 64				dc.font.descent = (*xfonts)->descent;
 65			xfonts++;
 66		}
 67	}
 68	else {
 69		if(dc.font.xfont)
 70			XFreeFont(dpy, dc.font.xfont);
 71		dc.font.xfont = NULL;
 72		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
 73			eprint("error, cannot load font: '%s'\n", fontstr);
 74		dc.font.ascent = dc.font.xfont->ascent;
 75		dc.font.descent = dc.font.xfont->descent;
 76	}
 77	dc.font.height = dc.font.ascent + dc.font.descent;
 78}
 79
 80static Bool
 81isoccupied(unsigned int t) {
 82	Client *c;
 83
 84	for(c = clients; c; c = c->next)
 85		if(c->tags[t])
 86			return True;
 87	return False;
 88}
 89
 90static unsigned int
 91textnw(const char *text, unsigned int len) {
 92	XRectangle r;
 93
 94	if(dc.font.set) {
 95		XmbTextExtents(dc.font.set, text, len, NULL, &r);
 96		return r.width;
 97	}
 98	return XTextWidth(dc.font.xfont, text, len);
 99}
100
101static void
102drawtext(const char *text, unsigned long col[ColLast]) {
103	int x, y, w, h;
104	static char buf[256];
105	unsigned int len, olen;
106	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
107
108	XSetForeground(dpy, dc.gc, col[ColBG]);
109	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
110	if(!text)
111		return;
112	w = 0;
113	olen = len = strlen(text);
114	if(len >= sizeof buf)
115		len = sizeof buf - 1;
116	memcpy(buf, text, len);
117	buf[len] = 0;
118	h = dc.font.ascent + dc.font.descent;
119	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
120	x = dc.x + (h / 2);
121	/* shorten text if necessary */
122	while(len && (w = textnw(buf, len)) > dc.w - h)
123		buf[--len] = 0;
124	if(len < olen) {
125		if(len > 1)
126			buf[len - 1] = '.';
127		if(len > 2)
128			buf[len - 2] = '.';
129		if(len > 3)
130			buf[len - 3] = '.';
131	}
132	if(w > dc.w)
133		return; /* too long */
134	XSetForeground(dpy, dc.gc, col[ColFG]);
135	if(dc.font.set)
136		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
137	else
138		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
139}
140
141/* extern */
142
143unsigned int bh;
144unsigned int bpos = BARPOS;
145DC dc = {0};
146Window barwin;
147
148void
149drawbar(void) {
150	int i, x;
151
152	dc.x = dc.y = 0;
153	for(i = 0; i < ntags; i++) {
154		dc.w = textw(tags[i]);
155		if(seltags[i]) {
156			drawtext(tags[i], dc.sel);
157			drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
158		}
159		else {
160			drawtext(tags[i], dc.norm);
161			drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
162		}
163		dc.x += dc.w;
164	}
165	dc.w = blw;
166	drawtext(getsymbol(), dc.norm);
167	x = dc.x + dc.w;
168	dc.w = textw(stext);
169	dc.x = sw - dc.w;
170	if(dc.x < x) {
171		dc.x = x;
172		dc.w = sw - x;
173	}
174	drawtext(stext, dc.norm);
175	if((dc.w = dc.x - x) > bh) {
176		dc.x = x;
177		if(sel) {
178			drawtext(sel->name, dc.sel);
179			drawsquare(sel->ismax, sel->isfloating, dc.sel);
180		}
181		else
182			drawtext(NULL, dc.norm);
183	}
184	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
185	XSync(dpy, False);
186}
187
188void
189initbar(void) {
190	XSetWindowAttributes wa;
191
192	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
193	dc.norm[ColBG] = initcolor(NORMBGCOLOR);
194	dc.norm[ColFG] = initcolor(NORMFGCOLOR);
195	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
196	dc.sel[ColBG] = initcolor(SELBGCOLOR);
197	dc.sel[ColFG] = initcolor(SELFGCOLOR);
198	initfont(FONT);
199	dc.h = bh = dc.font.height + 2;
200	wa.override_redirect = 1;
201	wa.background_pixmap = ParentRelative;
202	wa.event_mask = ButtonPressMask | ExposureMask;
203	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
204			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
205			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
206	XDefineCursor(dpy, barwin, cursor[CurNormal]);
207	updatebarpos();
208	XMapRaised(dpy, barwin);
209	strcpy(stext, "dwm-"VERSION);
210	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
211	dc.gc = XCreateGC(dpy, root, 0, 0);
212	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
213	if(!dc.font.set)
214		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
215}
216
217unsigned int
218textw(const char *text) {
219	return textnw(text, strlen(text)) + dc.font.height;
220}
221
222void
223togglebar(const char *arg) {
224	if(bpos == BarOff)
225		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
226	else
227		bpos = BarOff;
228	updatebarpos();
229	arrange();
230}
231
232void
233updatebarpos(void) {
234	XEvent ev;
235
236	wax = sx;
237	way = sy;
238	wah = sh;
239	waw = sw;
240	switch(bpos) {
241	default:
242		wah -= bh;
243		way += bh;
244		XMoveWindow(dpy, barwin, sx, sy);
245		break;
246	case BarBot:
247		wah -= bh;
248		XMoveWindow(dpy, barwin, sx, sy + wah);
249		break;
250	case BarOff:
251		XMoveWindow(dpy, barwin, sx, sy - bh);
252		break;
253	}
254	XSync(dpy, False);
255	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
256}
257
258