/* * xshow - put a 1-bit test pattern on a display and verify it landed. * * This is the display half, not XIE: it uses core X11 PutImage. It exists so * the VT1200 can be shown an image from this tree while the XIE 2.3 * create/photoflo/export path is still being recovered. The window title says * "core X", and the program prints that it is the fallback. * * Build: gcc -O2 -o xshow xshow.c -lX11 * Run: ./xshow -display 192.168.99.2:0 -width 640 -height 480 -seconds 30 */ #include #include #include #include #include #include #include static int bpl_for(int w) { return ((w + 31) / 32) * 4; } static void set_pixel(unsigned char *data, int bpl, int x, int y, int on) { unsigned char *p = data + y * bpl + (x >> 3); unsigned char bit = 1u << (x & 7); /* LSBFirst */ if (on) *p |= bit; else *p &= (unsigned char)~bit; } static void pattern(unsigned char *data, int w, int h, int bpl, const char *kind) { int x, y; memset(data, 0, (size_t)bpl * h); if (strcmp(kind, "solid") == 0) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) set_pixel(data, bpl, x, y, 1); } else if (strcmp(kind, "gradient") == 0) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) set_pixel(data, bpl, x, y, ((x * 16 / w) ^ (y * 16 / h)) & 1); } else if (strcmp(kind, "rings") == 0) { int cx = w / 2, cy = h / 2; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int dx = x - cx, dy = y - cy; int d = (dx * dx + dy * dy) / 64; set_pixel(data, bpl, x, y, (d / 16) & 1); } } else { /* checker */ int cell = w / 16; if (cell < 4) cell = 4; for (y = 0; y < h; y++) for (x = 0; x < w; x++) set_pixel(data, bpl, x, y, ((x / cell) + (y / cell)) & 1); } } int main(int argc, char **argv) { const char *display = "192.168.99.2:0"; const char *kind = "checker"; int w = 640, h = 480, seconds = 30; int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-display") && i + 1 < argc) display = argv[++i]; else if (!strcmp(argv[i], "-width") && i + 1 < argc) w = atoi(argv[++i]); else if (!strcmp(argv[i], "-height") && i + 1 < argc) h = atoi(argv[++i]); else if (!strcmp(argv[i], "-seconds") && i + 1 < argc) seconds = atoi(argv[++i]); else if (!strcmp(argv[i], "-pattern") && i + 1 < argc) kind = argv[++i]; else { fprintf(stderr, "usage: %s [-display host:0] [-width N] [-height N] " "[-seconds N] [-pattern checker|gradient|rings|solid]\n", argv[0]); return 2; } } Display *dpy = XOpenDisplay(display); if (!dpy) { fprintf(stderr, "xshow: cannot open %s\n", display); return 1; } int scr = DefaultScreen(dpy); Visual *vis = DefaultVisual(dpy, scr); int depth = DefaultDepth(dpy, scr); if (depth != 1) fprintf(stderr, "xshow: warning: depth is %d, expected 1\n", depth); int bpl = bpl_for(w); unsigned char *data = calloc((size_t)bpl, (size_t)h); if (!data) return 1; pattern(data, w, h, bpl, kind); Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 20, 20, (unsigned)w, (unsigned)h, 0, BlackPixel(dpy, scr), WhitePixel(dpy, scr)); XStoreName(dpy, win, "xshow: core X fallback (not XIE)"); XSelectInput(dpy, win, ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask); GC gc = XCreateGC(dpy, win, 0, NULL); XSetForeground(dpy, gc, BlackPixel(dpy, scr)); XSetBackground(dpy, gc, WhitePixel(dpy, scr)); XImage *img = XCreateImage(dpy, vis, (unsigned)depth, XYBitmap, 0, (char *)data, (unsigned)w, (unsigned)h, 32, bpl); if (!img) { fprintf(stderr, "xshow: XCreateImage failed\n"); return 1; } img->byte_order = LSBFirst; img->bitmap_bit_order = LSBFirst; XMapWindow(dpy, win); XPutImage(dpy, win, gc, img, 0, 0, 0, 0, (unsigned)w, (unsigned)h); XSync(dpy, False); /* Verify by reading the window back. A 1-bit XGetImage returns one * bit per pixel in the server's bit order; compare the on-pixel count * against the source rather than raw bytes. */ XImage *got = XGetImage(dpy, win, 0, 0, (unsigned)w, (unsigned)h, AllPlanes, ZPixmap); long src_on = 0, got_on = 0; int x, y; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned char *p = data + y * bpl + (x >> 3); if (p[0] & (1u << (x & 7))) src_on++; if (got && XGetPixel(got, x, y)) got_on++; } if (!got) { printf("xshow: displayed %dx%d %s on %s, but XGetImage failed\n", w, h, kind, display); } else { printf("xshow: displayed %dx%d %s on %s; source on-pixels=%ld " "window on-pixels=%ld %s\n", w, h, kind, display, src_on, got_on, (src_on == got_on) ? "MATCH" : "MISMATCH"); XDestroyImage(got); } printf("xshow: core X fallback window; XIE 2.3 export path is separate\n"); fflush(stdout); time_t end = time(NULL) + seconds; while (time(NULL) < end) { while (XPending(dpy)) { XEvent ev; XNextEvent(dpy, &ev); if (ev.type == KeyPress || ev.type == ButtonPress) { end = 0; break; } } usleep(100000); } XDestroyImage(img); /* also frees data */ XFreeGC(dpy, gc); XDestroyWindow(dpy, win); XCloseDisplay(dpy); return 0; }