aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rwxr-xr-xcolitur-mubin46728 -> 47040 bytes
-rw-r--r--mu_x11.c29
3 files changed, 40 insertions, 0 deletions
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
--- a/colitur-mu
+++ b/colitur-mu
Binary files 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 <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#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);
+ }
}