From 7459e218fa8b5b86c059762519447cb8863d3e75 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 21 Aug 2026 09:49:33 +0200 Subject: debug: MUX_DUMP writes one frame from the pixmap, then exits Verifying what the program actually draws by screenshotting its window is unreliable: X does not retain a window's contents while it is obscured or on an unfocused tag, so import and xwd can both return solid black while the rendering is correct. Reading back the off-screen pixmap always works. Used to confirm the XRectangle clip-truncation fix: rows now run unbroken from 2027-01-01 to 2027-01-29 with every column populated, where before the twelfth row lost everything but its name. --- README.md | 11 +++++++++++ colitur-mu | Bin 46728 -> 47040 bytes mu_x11.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/README.md b/README.md index 920c056..b0872cf 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,17 @@ and everything after it silently disappears, which looks like a layout or buffer-overflow bug and is neither. `set_clip()` clamps to the buffer bounds before converting. +### Verifying a frame without a screenshot + + MUX_DUMP=/tmp/frame.ppm ./colitur-mu # writes one frame, then exits + convert /tmp/frame.ppm /tmp/frame.png + +This reads back the off-screen PIXMAP, not the window. A window's contents +are not retained while it is obscured or sitting on an unfocused tag, so +`import`/`xwd` against one can return solid black while the program is +drawing perfectly -- which cost real time to work out once. A pixmap is +always there. + ### Which to use `colitur-x` renders; `colitur-mu` renders and lets you change the invocation. diff --git a/colitur-mu b/colitur-mu index ad4f4f7..eeaf02c 100755 Binary files a/colitur-mu and b/colitur-mu differ diff --git a/mu_x11.c b/mu_x11.c index 13b23c2..e672496 100644 --- a/mu_x11.c +++ b/mu_x11.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "vendor/microui.h" #include "mu_x11.h" @@ -145,4 +146,32 @@ void mux_present(mu_Context *ctx, int w, int h, mu_Color bg) XftDrawSetClip(xd, NULL); XCopyArea(dpy, buf, win, gc, 0, 0, w, h, 0, 0); XFlush(dpy); + + /* MUX_DUMP=path writes the frame out as a PPM and exits. Reading back + the off-screen PIXMAP rather than the window is what makes this + reliable: a window's contents are not retained when it is obscured or + on an unfocused tag, so screenshotting one can return black even + though the program is drawing perfectly. A pixmap is always there. */ + { + const char *path = getenv("MUX_DUMP"); + if (!path) return; + XImage *im = XGetImage(dpy, buf, 0, 0, w, h, AllPlanes, ZPixmap); + if (!im) { fprintf(stderr, "MUX_DUMP: XGetImage failed\n"); exit(1); } + FILE *f = fopen(path, "wb"); + if (!f) { fprintf(stderr, "MUX_DUMP: cannot write %s\n", path); exit(1); } + fprintf(f, "P6\n%d %d\n255\n", w, h); + for (int yy = 0; yy < h; yy++) + for (int xx = 0; xx < w; xx++) { + unsigned long px = XGetPixel(im, xx, yy); + unsigned char rgb[3] = { + (unsigned char)((px >> 16) & 0xff), + (unsigned char)((px >> 8) & 0xff), + (unsigned char)(px & 0xff) }; + fwrite(rgb, 1, 3, f); + } + fclose(f); + XDestroyImage(im); + fprintf(stderr, "MUX_DUMP: wrote %s (%dx%d)\n", path, w, h); + exit(0); + } } -- cgit v1.3