st-background-image-0.9.3.diff (17093B)
1 From 58b00ef34d4f8c34070f1544537f64b69bb91aab Mon Sep 17 00:00:00 2001 2 From: Matthias Schoth <mschoth@gmail.com> 3 Date: Sun, 8 Nov 2026 17:03:18 +0100 4 Subject: [PATCH] Add background image support via root window pixmap 5 6 Add a background image to st by tiling a server-side pixmap set as the 7 _ST_BACKGROUND_IMAGE root window property. st watches the root window 8 for property changes, so re-running the stbg setter updates all running 9 st instances immediately. 10 11 The pixmap is shared between all instances and no composite manager is 12 required. A pseudotransparency config option fixes the tile coordinates 13 to the screen origin so the terminal backgrounds line up with the 14 wallpaper behind the window. 15 16 stbg reads a farbfeld image from a file or stdin (using -) and sets the 17 property. It is not built by default; compile separately with: 18 19 cc -o stbg stbg.c -lX11 20 --- 21 config.def.h | 6 ++ 22 st.c | 2 +- 23 st.h | 1 + 24 stbg.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++ 25 x.c | 204 ++++++++++++++++++++++++++++++++++++--- 26 5 files changed, 464 insertions(+), 13 deletions(-) 27 create mode 100644 stbg.c 28 29 diff --git a/config.def.h b/config.def.h 30 index 2cd740a..3d98c87 100644 31 --- a/config.def.h 32 +++ b/config.def.h 33 @@ -8,6 +8,12 @@ 34 static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; 35 static int borderpx = 2; 36 37 +/* 38 + * pseudo transparency fixes coordinates to the screen origin 39 + * requires _ST_BACKGROUND_IMAGE root window property (set via stbg) 40 + */ 41 +static const int pseudotransparency = 0; 42 + 43 /* 44 * What program is execed by st depends of these precedence rules: 45 * 1: program passed with -e 46 diff --git a/st.c b/st.c 47 index 8e57991..2663816 100644 48 --- a/st.c 49 +++ b/st.c 50 @@ -194,7 +194,7 @@ static void tsetscroll(int, int); 51 static void tswapscreen(void); 52 static void tsetmode(int, int, const int *, int); 53 static int twrite(const char *, int, int); 54 -static void tfulldirt(void); 55 +void tfulldirt(void); 56 static void tcontrolcode(uchar ); 57 static void tdectest(char ); 58 static void tdefutf8(char); 59 diff --git a/st.h b/st.h 60 index fd3b0d8..a716a73 100644 61 --- a/st.h 62 +++ b/st.h 63 @@ -89,6 +89,7 @@ void toggleprinter(const Arg *); 64 int tattrset(int); 65 void tnew(int, int); 66 void tresize(int, int); 67 +void tfulldirt(void); 68 void tsetdirtattr(int); 69 void ttyhangup(void); 70 int ttynew(const char *, char *, const char *, char **); 71 diff --git a/stbg.c b/stbg.c 72 new file mode 100644 73 index 0000000..b984aa1 74 --- /dev/null 75 +++ b/stbg.c 76 @@ -0,0 +1,264 @@ 77 +/* See LICENSE file for copyright and license details. */ 78 +/* Build: cc -o stbg stbg.c -lX11 */ 79 +#include <errno.h> 80 +#include <limits.h> 81 +#include <stdarg.h> 82 +#include <stdio.h> 83 +#include <stdlib.h> 84 +#include <stdint.h> 85 +#include <string.h> 86 +#include <sys/stat.h> 87 +#include <unistd.h> 88 +#include <arpa/inet.h> 89 +#include <X11/Xlib.h> 90 +#include <X11/Xutil.h> 91 +#include <X11/Xatom.h> 92 + 93 +#define MAX_PIXELS (1u << 27) 94 + 95 +static char *argv0; 96 +static int xerr; 97 +static int xerror(Display *dpy, XErrorEvent *e) { (void)dpy; xerr = e->error_code; return 0; } 98 + 99 +static void 100 +die(const char *errstr, ...) 101 +{ 102 + va_list ap; 103 + 104 + fprintf(stderr, "%s: ", argv0); 105 + va_start(ap, errstr); 106 + vfprintf(stderr, errstr, ap); 107 + va_end(ap); 108 + exit(1); 109 +} 110 + 111 +static void 112 +usage(void) 113 +{ 114 + die("usage: %s file.ff\n %s - < file.ff\n", argv0, argv0); 115 +} 116 + 117 +static Pixmap 118 +getprev(Display *dpy, Window root) 119 +{ 120 + Atom prop = XInternAtom(dpy, "_ST_BACKGROUND_IMAGE", True); 121 + Atom actual_type; 122 + int actual_format; 123 + unsigned long nitems, bytes_after; 124 + unsigned char *prop_data = NULL; 125 + Pixmap prev = None; 126 + 127 + if (prop == None) 128 + return None; 129 + if (XGetWindowProperty(dpy, root, prop, 0, 1, False, XA_PIXMAP, 130 + &actual_type, &actual_format, &nitems, 131 + &bytes_after, &prop_data) != Success) 132 + return None; 133 + if (prop_data && nitems == 1 && actual_type == XA_PIXMAP && actual_format == 32) 134 + prev = *(Pixmap *)prop_data; 135 + if (prop_data) 136 + XFree(prop_data); 137 + return prev; 138 +} 139 + 140 +static int 141 +ispixmap(Display *dpy, Pixmap pm) 142 +{ 143 + XWindowAttributes wa; 144 + Window root; 145 + XErrorHandler oldh; 146 + int x, y, ok; 147 + unsigned int w, h, bw, depth; 148 + 149 + oldh = XSetErrorHandler(xerror); 150 + if (XGetWindowAttributes(dpy, pm, &wa)) { 151 + XSetErrorHandler(oldh); 152 + return 0; 153 + } 154 + ok = XGetGeometry(dpy, pm, &root, &x, &y, &w, &h, &bw, &depth); 155 + XSync(dpy, False); 156 + XSetErrorHandler(oldh); 157 + return ok; 158 +} 159 + 160 +static void 161 +killprev(Display *dpy, Pixmap prev) 162 +{ 163 + XErrorHandler oldh; 164 + 165 + if (prev == None || !ispixmap(dpy, prev)) 166 + return; 167 + oldh = XSetErrorHandler(xerror); 168 + XKillClient(dpy, prev); 169 + XSync(dpy, False); 170 + XSetErrorHandler(oldh); 171 +} 172 + 173 +static unsigned long 174 +channel(unsigned int v, unsigned long mask) 175 +{ 176 + unsigned long m = mask; 177 + int shift = 0, bits = 0; 178 + 179 + if (!mask) 180 + return 0; 181 + while (!(m & 1)) { 182 + m >>= 1; 183 + shift++; 184 + } 185 + while (m & 1) { 186 + bits++; 187 + m >>= 1; 188 + } 189 + return (((unsigned long)v * ((1UL << bits) - 1) + 32767) / 65535) << shift; 190 +} 191 + 192 +int 193 +main(int argc, char *argv[]) 194 +{ 195 + uint32_t hdr[4], w, h, size, x, y; 196 + uint64_t npixels; 197 + uint64_t *data; 198 + unsigned char *p; 199 + unsigned long pixel; 200 + FILE *f; 201 + int fromstdin; 202 + Pixmap pmap, prev; 203 + Display *dpy; 204 + Visual *vis; 205 + Window root; 206 + int scr, depth; 207 + Atom atom_stbg; 208 + GC gc; 209 + XGCValues gcvalues; 210 + XImage *xi; 211 + XErrorHandler oldh; 212 + 213 + argv0 = argv[0]; 214 + 215 + if (argc != 2) 216 + usage(); 217 + 218 + if (!(dpy = XOpenDisplay(NULL))) 219 + die("can't open display\n"); 220 + 221 + scr = DefaultScreen(dpy); 222 + root = RootWindow(dpy, scr); 223 + vis = DefaultVisual(dpy, scr); 224 + depth = DefaultDepth(dpy, scr); 225 + 226 + if (vis->class != TrueColor) 227 + die("unsupported visual class\n"); 228 + 229 + fromstdin = !strcmp(argv[1], "-"); 230 + f = fromstdin ? stdin : fopen(argv[1], "rb"); 231 + if (!fromstdin && !f) 232 + die("can't open %s\n", argv[1]); 233 + 234 + if (fread(hdr, sizeof(*hdr), 4, f) != 4) 235 + die("fread: unexpected end of file\n"); 236 + 237 + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) 238 + die("invalid farbfeld magic\n"); 239 + 240 + w = ntohl(hdr[2]); 241 + h = ntohl(hdr[3]); 242 + npixels = (uint64_t)w * h; 243 + if (w == 0 || h == 0 || w > INT_MAX / 4 || 244 + npixels > MAX_PIXELS || npixels > UINT32_MAX || 245 + npixels > SIZE_MAX / sizeof(uint64_t)) 246 + die("invalid farbfeld dimensions\n"); 247 + size = w * h; 248 + 249 + if (!fromstdin) { 250 + struct stat st; 251 + 252 + if (fstat(fileno(f), &st) == 0 && S_ISREG(st.st_mode) && 253 + (uint64_t)st.st_size < sizeof(hdr) + npixels * sizeof(uint64_t)) 254 + die("fread: unexpected end of file\n"); 255 + } 256 + 257 + data = malloc(size * sizeof(uint64_t)); 258 + if (!data) 259 + die("malloc: %s\n", strerror(errno)); 260 + 261 + if (fread(data, sizeof(uint64_t), size, f) != size) { 262 + free(data); 263 + die("fread: unexpected end of file\n"); 264 + } 265 + if (!fromstdin) 266 + fclose(f); 267 + 268 + xi = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0); 269 + if (!xi) { 270 + free(data); 271 + die("XCreateImage failed\n"); 272 + } 273 + xi->data = malloc((size_t)xi->bytes_per_line * h); 274 + if (!xi->data) { 275 + XDestroyImage(xi); 276 + free(data); 277 + die("malloc: %s\n", strerror(errno)); 278 + } 279 + p = (unsigned char *)data; 280 + for (y = 0; y < h; y++) { 281 + for (x = 0; x < w; x++, p += 8) { 282 + pixel = channel(((unsigned int)p[0] << 8) | p[1], vis->red_mask) | 283 + channel(((unsigned int)p[2] << 8) | p[3], vis->green_mask) | 284 + channel(((unsigned int)p[4] << 8) | p[5], vis->blue_mask); 285 + XPutPixel(xi, x, y, pixel); 286 + } 287 + } 288 + free(data); 289 + 290 + pmap = XCreatePixmap(dpy, root, w, h, depth); 291 + if (!pmap) { 292 + XDestroyImage(xi); 293 + die("XCreatePixmap failed\n"); 294 + } 295 + 296 + memset(&gcvalues, 0, sizeof(gcvalues)); 297 + gcvalues.graphics_exposures = False; 298 + gc = XCreateGC(dpy, pmap, GCGraphicsExposures, &gcvalues); 299 + if (!gc) { 300 + XDestroyImage(xi); 301 + die("XCreateGC failed\n"); 302 + } 303 + 304 + oldh = XSetErrorHandler(xerror); 305 + xerr = 0; 306 + XPutImage(dpy, pmap, gc, xi, 0, 0, 0, 0, w, h); 307 + XSync(dpy, False); 308 + XSetErrorHandler(oldh); 309 + if (xerr) { 310 + XDestroyImage(xi); 311 + XFreeGC(dpy, gc); 312 + die("XPutImage failed\n"); 313 + } 314 + XDestroyImage(xi); 315 + XFreeGC(dpy, gc); 316 + 317 + prev = getprev(dpy, root); 318 + 319 + XSetCloseDownMode(dpy, RetainPermanent); 320 + atom_stbg = XInternAtom(dpy, "_ST_BACKGROUND_IMAGE", False); 321 + oldh = XSetErrorHandler(xerror); 322 + xerr = 0; 323 + XChangeProperty(dpy, root, atom_stbg, XA_PIXMAP, 32, 324 + PropModeReplace, (unsigned char *)&pmap, 1); 325 + XSync(dpy, False); 326 + XSetErrorHandler(oldh); 327 + if (xerr) { 328 + XSetCloseDownMode(dpy, DestroyAll); 329 + XFreePixmap(dpy, pmap); 330 + die("XChangeProperty failed\n"); 331 + } 332 + if (prev != None) { 333 + usleep(200000); 334 + killprev(dpy, prev); 335 + } 336 + XSync(dpy, False); 337 + XCloseDisplay(dpy); 338 + 339 + return 0; 340 +} 341 diff --git a/x.c b/x.c 342 index d73152b..f75f2aa 100644 343 --- a/x.c 344 +++ b/x.c 345 @@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec; 346 typedef struct { 347 int tw, th; /* tty width and height */ 348 int w, h; /* window width and height */ 349 + int x, y; /* window location */ 350 int ch; /* char height */ 351 int cw; /* char width */ 352 int mode; /* window state/mode flags */ 353 @@ -101,6 +102,9 @@ typedef struct { 354 XVaNestedList spotlist; 355 } ime; 356 Draw draw; 357 + GC bggc; /* Graphics Context for background */ 358 + Atom stbg_atom; /* _ST_BACKGROUND_IMAGE atom */ 359 + Atom netwmstate_atom; /* _NET_WM_STATE atom */ 360 Visual *vis; 361 XSetWindowAttributes attrs; 362 int scr; 363 @@ -111,6 +115,7 @@ typedef struct { 364 365 typedef struct { 366 Atom xtarget; 367 + Atom incrprop; /* property of an in-progress INCR transfer */ 368 char *primary, *clipboard; 369 struct timespec tclick1; 370 struct timespec tclick2; 371 @@ -151,6 +156,9 @@ static void ximinstantiate(Display *, XPointer, XPointer); 372 static void ximdestroy(XIM, XPointer, XPointer); 373 static int xicdestroy(XIC, XPointer, XPointer); 374 static void xinit(int, int); 375 +static void bginit(void); 376 +static Pixmap bginitfromroot(void); 377 +static void updatexy(void); 378 static void cresize(int, int); 379 static void xresize(int, int); 380 static void xhints(void); 381 @@ -220,6 +228,44 @@ static DC dc; 382 static XWindow xw; 383 static XSelection xsel; 384 static TermWindow win; 385 +static int posdirty = 1; /* window may have moved; re-sync tile origin */ 386 +static int bggone; 387 +static int xprobe; 388 +static int xprobeerr; 389 +static XErrorHandler oldxerror; 390 + 391 +static int 392 +ispixmap(Pixmap pm, Window *root, unsigned int *depth) 393 +{ 394 + XWindowAttributes wa; 395 + int x, y, ok; 396 + unsigned int w, h, bw; 397 + 398 + xprobe = 1; 399 + if (XGetWindowAttributes(xw.dpy, pm, &wa)) { 400 + xprobe = 0; 401 + return 0; 402 + } 403 + xprobeerr = 0; 404 + ok = XGetGeometry(xw.dpy, pm, root, &x, &y, &w, &h, &bw, depth); 405 + xprobe = 0; 406 + return ok && !xprobeerr; 407 +} 408 + 409 +static int 410 +xerror(Display *dpy, XErrorEvent *e) 411 +{ 412 + if (xprobe) { 413 + xprobeerr = 1; 414 + return 0; 415 + } 416 + if (e->error_code == BadPixmap || e->error_code == BadDrawable || 417 + e->error_code == BadMatch) { 418 + bggone = 1; 419 + return 0; 420 + } 421 + return oldxerror ? oldxerror(dpy, e) : 0; 422 +} 423 424 /* Font Ring Cache */ 425 enum { 426 @@ -510,11 +556,29 @@ propnotify(XEvent *e) 427 Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); 428 429 xpev = &e->xproperty; 430 + /* 431 + * propnotify is only used for incremental transfers. With 432 + * pseudotransparency PropertyChangeMask is kept enabled all the 433 + * time, so ordinary selection property changes arrive here too; 434 + * processing them would paste the selection a second time. 435 + */ 436 if (xpev->state == PropertyNewValue && 437 (xpev->atom == XA_PRIMARY || 438 - xpev->atom == clipboard)) { 439 + xpev->atom == clipboard) && 440 + xsel.incrprop == xpev->atom) { 441 selnotify(e); 442 } 443 + 444 + if (xpev->atom == xw.stbg_atom) { 445 + bginit(); 446 + redraw(); 447 + return; 448 + } 449 + 450 + if (pseudotransparency && 451 + e->xproperty.atom == xw.netwmstate_atom) { 452 + redraw(); 453 + } 454 } 455 456 void 457 @@ -536,6 +600,9 @@ selnotify(XEvent *e) 458 if (property == None) 459 return; 460 461 + if (e->type == SelectionNotify) 462 + xsel.incrprop = None; 463 + 464 do { 465 if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, 466 BUFSIZ/4, False, AnyPropertyType, 467 @@ -552,9 +619,12 @@ selnotify(XEvent *e) 468 * data has been transferred. We won't need to receive 469 * PropertyNotify events anymore. 470 */ 471 - MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); 472 - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, 473 - &xw.attrs); 474 + xsel.incrprop = None; 475 + if (!pseudotransparency) { 476 + MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); 477 + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, 478 + &xw.attrs); 479 + } 480 } 481 482 if (type == incratom) { 483 @@ -563,9 +633,12 @@ selnotify(XEvent *e) 484 * when the selection owner does send us the next 485 * chunk of data. 486 */ 487 - MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); 488 - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, 489 + xsel.incrprop = property; 490 + if (!pseudotransparency) { 491 + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); 492 + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, 493 &xw.attrs); 494 + } 495 496 /* 497 * Deleting the property is the transfer start signal. 498 @@ -851,9 +924,13 @@ xsetcolorname(int x, const char *name) 499 void 500 xclear(int x1, int y1, int x2, int y2) 501 { 502 - XftDrawRect(xw.draw, 503 - &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], 504 - x1, y1, x2-x1, y2-y1); 505 + if (IS_SET(MODE_REVERSE)) { 506 + XftDrawRect(xw.draw, &dc.col[defaultfg], x1, y1, x2-x1, y2-y1); 507 + return; 508 + } 509 + if (pseudotransparency) 510 + XSetTSOrigin(xw.dpy, xw.bggc, -win.x, -win.y); 511 + XFillRectangle(xw.dpy, xw.buf, xw.bggc, x1, y1, x2-x1, y2-y1); 512 } 513 514 void 515 @@ -1137,6 +1214,7 @@ xinit(int cols, int rows) 516 517 if (!(xw.dpy = XOpenDisplay(NULL))) 518 die("can't open display\n"); 519 + oldxerror = XSetErrorHandler(xerror); 520 xw.scr = XDefaultScreen(xw.dpy); 521 xw.vis = XDefaultVisual(xw.dpy, xw.scr); 522 523 @@ -1242,6 +1320,87 @@ xinit(int cols, int rows) 524 xsel.xtarget = XA_STRING; 525 } 526 527 +void 528 +bginit(void) 529 +{ 530 + XGCValues gcvalues; 531 + Pixmap bgpmap; 532 + 533 + if (xw.bggc) 534 + XFreeGC(xw.dpy, xw.bggc); 535 + 536 + memset(&gcvalues, 0, sizeof(gcvalues)); 537 + xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues); 538 + 539 + bgpmap = bginitfromroot(); 540 + 541 + if (bgpmap == None) { 542 + XSetForeground(xw.dpy, xw.bggc, dc.col[defaultbg].pixel); 543 + XSetFillStyle(xw.dpy, xw.bggc, FillSolid); 544 + } 545 + 546 + if (pseudotransparency) { 547 + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); 548 + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); 549 + } 550 + 551 + xw.stbg_atom = XInternAtom(xw.dpy, "_ST_BACKGROUND_IMAGE", False); 552 + xw.netwmstate_atom = XInternAtom(xw.dpy, "_NET_WM_STATE", False); 553 + XSelectInput(xw.dpy, DefaultRootWindow(xw.dpy), PropertyChangeMask); 554 +} 555 + 556 +/* 557 + * initialize background image from root window _ST_BACKGROUND_IMAGE 558 + */ 559 +static Pixmap 560 +bginitfromroot(void) 561 +{ 562 + Atom prop, atom_type; 563 + int format; 564 + unsigned long nitems, after; 565 + unsigned char *data; 566 + Pixmap pmap; 567 + 568 + prop = XInternAtom(xw.dpy, "_ST_BACKGROUND_IMAGE", True); 569 + if (prop == None) 570 + return None; 571 + 572 + if (XGetWindowProperty(xw.dpy, DefaultRootWindow(xw.dpy), prop, 573 + 0, 1, False, AnyPropertyType, &atom_type, 574 + &format, &nitems, &after, &data) != Success) 575 + return None; 576 + 577 + if (atom_type != XA_PIXMAP || format != 32 || nitems < 1) { 578 + XFree(data); 579 + return None; 580 + } 581 + 582 + pmap = *(Pixmap *)data; 583 + XFree(data); 584 + 585 + { 586 + Window rr; 587 + unsigned int dep; 588 + 589 + if (!ispixmap(pmap, &rr, &dep) || 590 + rr != DefaultRootWindow(xw.dpy) || 591 + dep != DefaultDepth(xw.dpy, xw.scr)) 592 + return None; 593 + } 594 + 595 + XSetTile(xw.dpy, xw.bggc, pmap); 596 + XSetFillStyle(xw.dpy, xw.bggc, FillTiled); 597 + return pmap; 598 +} 599 + 600 +void 601 +updatexy(void) 602 +{ 603 + Window child; 604 + XTranslateCoordinates(xw.dpy, xw.win, DefaultRootWindow(xw.dpy), 0, 0, 605 + &win.x, &win.y, &child); 606 +} 607 + 608 int 609 xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) 610 { 611 @@ -1482,7 +1641,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 612 xclear(winx, winy + win.ch, winx + width, win.h); 613 614 /* Clean up the region we want to draw to. */ 615 - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 616 + if (bg == &dc.col[defaultbg]) 617 + xclear(winx, winy, winx + width, winy + win.ch); 618 + else 619 + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 620 621 /* Set the clip region because Xft is sometimes dirty. */ 622 r.x = 0; 623 @@ -1651,6 +1813,17 @@ xsettitle(char *p) 624 int 625 xstartdraw(void) 626 { 627 + if (bggone && IS_SET(MODE_VISIBLE)) { 628 + bggone = 0; 629 + bginit(); 630 + tfulldirt(); 631 + } 632 + if (pseudotransparency && IS_SET(MODE_VISIBLE)) { 633 + if (posdirty) { 634 + updatexy(); 635 + posdirty = 0; 636 + } 637 + } 638 return IS_SET(MODE_VISIBLE); 639 } 640 641 @@ -1914,9 +2087,15 @@ cmessage(XEvent *e) 642 void 643 resize(XEvent *e) 644 { 645 - if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) 646 - return; 647 + if (pseudotransparency && 648 + (e->xconfigure.x != win.x || e->xconfigure.y != win.y)) 649 + posdirty = 1; 650 651 + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) { 652 + if (pseudotransparency && posdirty) 653 + tfulldirt(); 654 + return; 655 + } 656 cresize(e->xconfigure.width, e->xconfigure.height); 657 } 658 659 @@ -2100,6 +2279,7 @@ run: 660 rows = MAX(rows, 1); 661 tnew(cols, rows); 662 xinit(cols, rows); 663 + bginit(); 664 xsetenv(); 665 selinit(); 666 run(); 667 -- 668 2.55.0 669