#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>

#define W 640
#define H 256

int main(int argc, char **argv) {
    Display *d;
    int scrn;
    Screen *s;
    Window w;
    Window root;
    XShmSegmentInfo xshmi;
    XImage *xi;
    int i, j, k;
    GC gc;
    XGCValues gcv;
    long *fast_mem;

    if (NULL == (d = XOpenDisplay(NULL))) {
	fprintf(stderr, "Cannot open display.\n");
	return 1;
    }

    root = DefaultRootWindow(d);
    scrn = DefaultScreen(d);

    /* create window */
    w = XCreateSimpleWindow(d, root, 0, 0, W, H, 0,
			    BlackPixel(d, scrn), WhitePixel(d, scrn));
    XMapRaised(d, w);

    /* create XImage - it's data is the shared memory segment */
    xi = XShmCreateImage(d, DefaultVisual(d, scrn), DefaultDepth(d, scrn),
			 ZPixmap, NULL, &xshmi, W, H);

    /* create shared memory */
    xshmi.shmid = shmget(IPC_PRIVATE, xi->bytes_per_line * xi->height,
			 IPC_CREAT | 0777);
    if (-1 == xshmi.shmid) {
	perror("shmget");
	return 1;
    }

    xi->data = xshmi.shmaddr = shmat(xshmi.shmid, 0, 0);
    xshmi.readOnly = False;
    /* See /usr/include/X11.h for "ERROR CODES" */
    printf("XShmAttach() = %d\n", XShmAttach(d, &xshmi));


    /* remove shared memory - it'll still be available as we've got access to
     * it. But upon exit the system will tidy up for us.
     */
    /* shmctl(xshmi.shmid, IPC_RMID, NULL); */

    /* create the GC */
    gcv.foreground = BlackPixel(d, scrn);
    gcv.function = GXcopy;
    gc = XCreateGC(d, w, GCFunction | GCForeground | GCFunction, &gcv);

    /* initialise the display */
    XDrawLine(d, w, gc, 0, 0, 639, 255);
    XSync(d, False);
    sleep(1);

    for (i = 1; i <= H; i++) {
	for (j = i; j < W/2; j++) {
	    xshmi.shmaddr[i*W-j] = H-i;
	}
	for (j = W/2; j < W-i; j++) {
	    xshmi.shmaddr[i*W-j] = i;
	}
    }

    sleep(2);

    for (;;) {
	j = 255;
	for (i = 0; i < W*H; i++) {
	    xshmi.shmaddr[i] ^= j;
	    j = xshmi.shmaddr[i];
	}
	XShmPutImage(d, w, gc, xi, 0, 0, 0, 0, W, H, False);
	XSync(d,False);
    }

    return 0;
}
