swm

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

bar.c (6554B)


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