swm

sigma window manager
git clone git://wolog.xyz/swm
Log | Files | Refs | README | LICENSE

bar.c (6744B)


      1 /*
      2  * Copyright (C) Raymond Cole <rc@wolog.xyz>
      3  *
      4  * Licensed under the GNU General Public License; either version 3 of
      5  * the License, or (at your option) any later version.  See the LICENSE
      6  * file for details.
      7  *
      8  * Portions of the code originally belong to dwm as developed by Anselm
      9  * R. Garbe et al.  See LICENSE-dwm for the copyright and license details
     10  * of those portions.
     11  */
     12 #include <fcntl.h>
     13 #include <errno.h>
     14 #include <poll.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <unistd.h>
     19 #include <X11/Xatom.h>
     20 #include <X11/Xlib.h>
     21 #include <X11/Xutil.h>
     22 #include <X11/Xft/Xft.h>
     23 
     24 #include "drw.h"
     25 #include "swm.h"
     26 #include "util.h"
     27 
     28 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
     29 
     30 int barh;
     31 int sfdw = -1, sfdr = -1;
     32 
     33 static Drw *drw;
     34 static Scm *schemesel;
     35 static Scm *schemenorm;
     36 
     37 static int lrpad, boxs, boxw;
     38 
     39 static char blocks[256];
     40 static size_t nblocks;
     41 static int blockw[(sizeof(blocks) - 1) / 2];
     42 static int blocklpad[LENGTH(blockw) + 1];
     43 
     44 void
     45 barsetup(void)
     46 {
     47 	if (!(drw = drw_create(dpy, screen, root, sw, sh)))
     48 		die("cannot create drawer object");
     49 	if (!drw_fontset_create(drw, fonts, nfonts))
     50 		die("cannot load fonts");
     51 	lrpad = drw->fonts->h;
     52 	boxs = drw->fonts->h / 9;
     53 	boxw = drw->fonts->h / 6 + 2;
     54 	barh = drw->fonts->h + 2;
     55 	if (!(schemesel = drw_scm_create(drw, colsf, colsb))
     56 	|| !(schemenorm = drw_scm_create(drw, colnf, colnb)))
     57 		die("cannot create color schemes");
     58 }
     59 
     60 void
     61 barcleanup(void)
     62 {
     63 	free(schemenorm);
     64 	free(schemesel);
     65 	drw_free(drw);
     66 }
     67 
     68 void
     69 initbar(Monitor *m)
     70 {
     71 	static XSetWindowAttributes wa = {
     72 		.override_redirect = True,
     73 		.background_pixmap = ParentRelative,
     74 		.event_mask = ButtonPressMask|ExposureMask
     75 	};
     76 	static XClassHint ch = { "swm", "swm" };
     77 
     78 	m->barwin = XCreateWindow(dpy, root, m->x, BY(m), m->w, barh, 0,
     79 	                          DefaultDepth(dpy, screen), CopyFromParent,
     80 	                          DefaultVisual(dpy, screen),
     81 	                          CWOverrideRedirect|CWBackPixmap|CWEventMask,
     82 	                          &wa);
     83 	XDefineCursor(dpy, m->barwin, curnormal);
     84 	XMapRaised(dpy, m->barwin);
     85 	XSetClassHint(dpy, m->barwin, &ch);
     86 }
     87 
     88 void
     89 runsprog(void)
     90 {
     91 	int fds[2];
     92 	pid_t pid;
     93 
     94 	if (!statusprog)
     95 		return;
     96 	if (sfdr >= 0 || sfdw >= 0)
     97 		endsprog();
     98 	switch ((pid = depart(fds))) {
     99 	case -1:
    100 		warn("cannot run status program");
    101 		return;
    102 	case 0:
    103 		execvp(statusprog[0], statusprog);
    104 		die("execvp '%s':", statusprog[0]);
    105 	default:
    106 		break;
    107 	}
    108 	sfdr = fds[0];
    109 	sfdw = fds[1];
    110 	if (fcntl(sfdr, F_SETFL, O_NONBLOCK) < 0
    111 	 || fcntl(sfdr, F_SETFD, FD_CLOEXEC) < 0) {
    112 		warn("cannot set up read end for status: fcntl:");
    113 		endsprog();
    114 	}
    115 }
    116 
    117 void
    118 endsprog(void)
    119 {
    120 	if (sfdr >= 0)
    121 		close(sfdr);
    122 	if (sfdw >= 0)
    123 		close(sfdw);
    124 	sfdr = sfdw = -1;
    125 }
    126 
    127 void
    128 updatedrawable(void)
    129 {
    130 	drw_resize(drw, sw, barh);
    131 }
    132 
    133 void
    134 updatestatus(void)
    135 {
    136 	char *b, *p;
    137 	unsigned i, n;
    138 	char buf[sizeof(blocks)];
    139 	int r, e, t;
    140 	struct pollfd fd[1];
    141 
    142 	if (sfdr < 0) {
    143 		nblocks = 0;
    144 		pdrawbar(selmon);
    145 		return;
    146 	}
    147 	for (n = 0; (r = read(sfdr, buf, sizeof(buf))); n += r) {
    148 		if (r < 0) {
    149 			e = errno;
    150 			if (e == EAGAIN && n && blocks[n - 1] != '\n') {
    151 				fd->fd = sfdr;
    152 				fd->events = POLLIN;
    153 				if (poll(fd, 1, 1000) == 1) {
    154 					r = 0;
    155 					continue;
    156 				}
    157 			}
    158 			break;
    159 		}
    160 		if (n + r <= sizeof(blocks)) {
    161 			memcpy(blocks + n, buf, r);
    162 		} else {
    163 			memmove(blocks, blocks + n + r - sizeof(blocks),
    164 				sizeof(blocks) - r);
    165 			memcpy(blocks + sizeof(blocks) - r, buf, r);
    166 			n = sizeof(blocks) - r;
    167 		}
    168 	}
    169 	if (!r)
    170 		e = 0;
    171 	if (e == EAGAIN && !n)
    172 		return;
    173 	if (e != EAGAIN && e) {
    174 		errno = e;
    175 		warn("read:");
    176 	}
    177 	if (e != EAGAIN || !n || blocks[n - 1] != '\n') {
    178 		endsprog();
    179 		nblocks = 0;
    180 		pdrawbar(selmon);
    181 		return;
    182 	}
    183 	blocks[--n] = '\0';
    184 	if ((b = strrchr(blocks, '\n')))
    185 		memmove(blocks, b + 1, blocks + n - b);
    186 	nblocks = 0;
    187 	b = p = blocks;
    188 	p += t = strspn(p, " ");
    189 	while (*p) {
    190 		blocklpad[nblocks++] = t * lrpad / 2;
    191 		while (*p && (*p != ' ' || (p[1] && p[1] != ' ')))
    192 			*b++ = *p++;
    193 		p += t = strspn(p, " ");
    194 		*b++ = '\0';
    195 	}
    196 	for (i = 0, b = blocks; i < nblocks; ++i, b += strlen(b) + 1)
    197 		blockw[i] = TEXTW(b) - lrpad + blocklpad[i];
    198 	for (i = 1; i < nblocks; ++i) {
    199 		blocklpad[i] -= r = blocklpad[i] / 2;
    200 		blockw[i] -= r;
    201 		blockw[i - 1] += r;
    202 	}
    203 	if (t)
    204 		blockw[nblocks - 1] += t * lrpad / 2;
    205 	pdrawbar(selmon);
    206 }
    207 
    208 void
    209 drawbar(Monitor *m)
    210 {
    211 	unsigned occ = 0, urg = 0;
    212 	unsigned i, j;
    213 	int x, w, lw;
    214 	Client *c;
    215 	char *b;
    216 
    217 	if (!m->showbar)
    218 		return;
    219 	for (c = m->clients; c; c = c->next) {
    220 		occ |= c->tags;
    221 		if (c->isurgent && !ISVISIBLE(c))
    222 			urg |= c->tags;
    223 	}
    224 	x = 0;
    225 	for (i = 0; i < LENGTH(tags); ++i) {
    226 		w = TEXTW(tags[i]);
    227 		drw_setscheme(drw, m->tagset & 1 << i ? schemesel : schemenorm);
    228 		drw_text(drw, x, 0, w, barh, lrpad / 2, tags[i], urg & 1 << i);
    229 		if (i == m->selws)
    230 			drw_rect(drw, x + boxw, barh - boxs,
    231 			         w - boxw * 2, boxs, 1, 0);
    232 		if (occ & 1 << i)
    233 			drw_rect(drw, x + boxs, boxs, boxw, boxw,
    234 			         m == selmon && selmon->sel
    235 			         && (selmon->sel->tags & 1 << i),
    236 			         urg & 1 << i);
    237 		x += w;
    238 	}
    239 	m->tagsw = x;
    240 	if (m->lyt) {
    241 		lw = TEXTW(m->lytdesc);
    242 		drw_setscheme(drw, schemenorm);
    243 		x = drw_text(drw, x, 0, lw, barh, lrpad / 2, m->lytdesc, 0);
    244 	} else {
    245 		lw = 0;
    246 	}
    247 	w = 0;
    248 	if (m == selmon && m->w > x) {
    249 		drw_setscheme(drw, schemenorm);
    250 		i = nblocks;
    251 		while (i && w + blockw[i - 1] <= m->w - x)
    252 			w += blockw[--i];
    253 		for (b = blocks, j = 0; j < i; ++j)
    254 			b += strlen(b) + 1;
    255 		x = m->w - w;
    256 		for (; i < nblocks; ++i) {
    257 			x = drw_text(drw, x, 0, blockw[i], barh,
    258 			             blocklpad[i], b, 0);
    259 			b += strlen(b) + 1;
    260 		}
    261 	}
    262 	m->statusw = w;
    263 	x = m->tagsw + lw;
    264 	if (m->w > x + m->statusw) {
    265 		w = m->w - x - m->statusw;
    266 		if (m->sel) {
    267 			drw_setscheme(drw, m == selmon? schemesel: schemenorm);
    268 			drw_text(drw, x, 0, w, barh, lrpad / 2, m->sel->title, 0);
    269 			if (!m->sel->hintsvalid)
    270 				updatesizehints(m->sel);
    271 			if (m->sel->isfloating)
    272 				drw_rect(drw, x + boxs, boxs, boxw, boxw,
    273 				         m->sel->isfixed, 0);
    274 		} else {
    275 			drw_setscheme(drw, schemenorm);
    276 			drw_rect(drw, x, 0, w, barh, 1, 1);
    277 		}
    278 	}
    279 	drw_map(drw, m->barwin, 0, 0, m->w, barh);
    280 }
    281 
    282 int
    283 posinbar(Monitor *m, int clkx, int *n)
    284 {
    285 	int x, i;
    286 
    287 	if (clkx >= m->w - m->statusw) {
    288 		if (!n)
    289 			return BarStatus;
    290 		for (x = m->w, i = nblocks; i--;) {
    291 			x -= blockw[i];
    292 			if (x <= clkx) {
    293 				*n = nblocks - i;
    294 				return BarStatus;
    295 			}
    296 		}
    297 	} else if (clkx < m->tagsw) {
    298 		if (!n)
    299 			return BarTags;
    300 		for (x = i = 0; i < LENGTH(tags); ++i) {
    301 			x += TEXTW(tags[i]);
    302 			if (x > clkx) {
    303 				*n = i;
    304 				return BarTags;
    305 			}
    306 		}
    307 	} else if (clkx < m->tagsw + TEXTW(m->lytdesc)) {
    308 		return BarLytDesc;
    309 	} else {
    310 		return BarWinTitle;
    311 	}
    312 	return -1;
    313 }