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 }