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 }