Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!ucsd!ucbvax!hplabs!hpfcso!hpfcdq!stroyan From: stroyan@hpfcdq.HP.COM (Mike Stroyan) Newsgroups: comp.windows.x Subject: Re: X double buffering Message-ID: <890041@hpfcdq.HP.COM> Date: 17 Oct 89 22:54:10 GMT References: <181@wbcs.UUCP> Organization: Hewlett-Packard - Fort Collins, CO Lines: 410 > Could someone give me hints, code fragments, or examples > on "double-buffering" with X? > Doug Kratky Below is a set of utility functions for double buffering in X. The functions use colormap manipulation; they therefore require a dynamic visual such as GrayScale, PseudoColor or DirectColor. The example program will fail if the default visual is not dynamic or has less than 16 free colors. There is also a more subtle requirement of grouping by planes, so the program may fail even though 16 colors are free. A program could avoid many of these hurdles by creating a window with an appropriate visual and a private colormap. You then have to handle the colormap focus issues. Mike Stroyan, stroyan@hpfcla.hp.com # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Mike Stroyan on Tue Oct 17 16:48:15 1989 # # This archive contains: # Makefile dbuf.c double_buf.c double_buf.h # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - Makefile cat >Makefile <<'@EOF' CFLAGS= -O LDFLAGS= -lX11 -lm dbuf: dbuf.c double_buf.o $(CC) $(CFLAGS) -o dbuf dbuf.c double_buf.o -lX11 -lm @EOF chmod 664 Makefile echo x - dbuf.c cat >dbuf.c <<'@EOF' /* dbuf.c - a demonstration of double buffering under X windows */ #include #include #include #include #include #include #include "double_buf.h" #define POINTS 6 main(argc, argv) int argc; char *argv[]; { Display *display; Window w1, w2; GC gc1, gc2; XGCValues gcvalues; XColor colors[4]; XPoint data[POINTS]; double_buffer_state *dbuf_state; double start_angle, angle; register int i; struct timeval timeout; XEvent event; static XSizeHints xsh = { /* Size hints for window manager */ (PPosition | PSize | PMinSize), /* flags */ 400, /* height */ 400, /* width */ 200, /* minimum height */ 200, /* minimum width */ 300, /* x coordinate */ 200 /* y coordinate */ }; static XWMHints xwmh = { /* More hints for window manager */ (InputHint | StateHint), /* flags */ False, /* input */ NormalState, /* initial_state */ 0, /* icon pixmap */ 0, /* icon window */ 0, 0, /* icon location */ 0, /* icon mask */ 0, /* Window group */ }; static XClassHint xch = { /* Class hints for window manager */ "Dbuf", /* name */ "Dbuf" /* class */ }; timeout.tv_sec = 0; timeout.tv_usec = 50000; if ((display = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "Can't open %s\n", XDisplayName(NULL)); exit(1); } /* * Create two windows. * Window w1 will be double buffered. * Window w2 won't be. */ w1 = XCreateSimpleWindow(display, DefaultRootWindow(display), xsh.x, xsh.y, xsh.width, xsh.height, 2, WhitePixel(display, DefaultScreen(display)), BlackPixel(display, DefaultScreen(display))); if (!w1) { fprintf (stderr, "XCreateSimpleWindow failed\n"); exit(1); } gc1 = XCreateGC(display, w1, 0, &gcvalues); XSetStandardProperties(display, w1, "double buffered", "double buffered", None, argv, argc, &xsh); XSetWMHints(display, w1, &xwmh); XSetClassHint(display, w1, &xch); XSelectInput(display, w1, StructureNotifyMask | ButtonPressMask); XMapWindow(display, w1); XFlush(display); do { XNextEvent(display, &event); } while (event.type != MapNotify || event.xmap.window != w1); xsh.x = 600; w2 = XCreateSimpleWindow(display, DefaultRootWindow(display), xsh.x, xsh.y, xsh.width, xsh.height, 2, WhitePixel(display, DefaultScreen(display)), BlackPixel(display, DefaultScreen(display))); if (!w2) { fprintf (stderr, "XCreateSimpleWindow failed\n"); exit(1); } gc2 = XCreateGC(display, w2, 0, gcvalues); XSetStandardProperties(display, w2, "single buffered", "single buffered", None, argv, argc, &xsh); XSetWMHints(display, w2, &xwmh); XSetClassHint(display, w2, &xch); XSelectInput(display, w2, StructureNotifyMask | ButtonPressMask); XMapWindow(display, w2); XFlush(display); do { XNextEvent(display, &event); } while (event.type != MapNotify || event.xmap.window != w2); /* black */ colors[0].red = 0; colors[0].green = 0; colors[0].blue = 0; /* white */ colors[1].red = 65535; colors[1].green = 65535; colors[1].blue = 65535; /* green */ colors[2].red = 0; colors[2].green = 40000; colors[2].blue = 0; /* yellow */ colors[3].red = 65535; colors[3].green = 65535; colors[3].blue = 0; dbuf_state = start_double_buffer(display, DefaultColormap(display, DefaultScreen(display)), 2, colors); if (dbuf_state == NULL) { fprintf(stderr, "Couldn't allocate resources for double buffering\n"); exit(1); } XSetPlaneMask(display, gc1, dbuf_state->drawing_planes); start_angle = 0.0; while (XPending(display) == 0) { start_angle += M_PI / 50.0; angle = start_angle; for (i=0; idrawing_planes); XFlush(display); select(0, 0, 0, 0, &timeout); } end_double_buffer(dbuf_state); XCloseDisplay(display); exit(0); } @EOF chmod 666 dbuf.c echo x - double_buf.c cat >double_buf.c <<'@EOF' /* * double_buf.c - an Xlib double buffering utility. */ #include #include #include #include "double_buf.h" static void release(state) register double_buffer_state *state; /* * Release a possibly partially allocated double buffer state record. */ { if (state != NULL) { if (state->colormaps[0] != NULL) free(state->colormaps[0]); if (state->colormaps[1] != NULL) free(state->colormaps[1]); if (state->planes != NULL) free(state->planes); free(state); } } static long color(state, simple_color) register double_buffer_state *state; register long simple_color; /* * Map the supplied color into the equivalent color * using the double buffered planes. */ { register long i, plane, computed_color; computed_color = state->pixel; for (plane = 1, i = 0; simple_color != 0; plane <<= 1, i++) { if (plane & simple_color) { computed_color |= state->planes[i]; simple_color &= ~plane; } } return(computed_color); } double_buffer_state *start_double_buffer(display, cmap, planes, colors) Display *display; Colormap cmap; long planes; /* how many planes for each buffer */ XColor *colors; /* color settings for buffers */ /* * Start double buffering in given number of planes per buffer. * If resources can be allocated, then set color pixels in colors parameter * and return the address of a double_buffer_state record. * Otherwise, return NULL. */ { register double_buffer_state *state; register long i, high_mask, low_mask; /* Allocate memory. */ state = (double_buffer_state *) malloc(sizeof(double_buffer_state)); if (state == NULL) return (NULL); state->map_size = 1 << (2 * planes); state->colormaps[0] = (XColor *) malloc(state->map_size * sizeof(XColor)); state->colormaps[1] = (XColor *) malloc(state->map_size * sizeof(XColor)); state->planes = (long *) malloc((2 * planes) * sizeof(long)); if (state->colormaps[1] == NULL || state->colormaps[0] == NULL || state->planes == NULL) { release(state); return(NULL); } state->display = display; state->cmap = cmap; /* Get colors to double buffer with. */ if (XAllocColorCells(state->display, state->cmap, False, state->planes, 2*planes, &state->pixel, 1) == 0) { release(state); return(NULL); } /* Prepare the write enable masks. */ state->masks[0] = AllPlanes; state->masks[1] = AllPlanes; /* Mask 0 won't write in the "low" planes. */ /* Mask 1 won't write in the "high" planes. */ for (i = 0; i < planes; i++) { state->masks[0] &= ~state->planes[i]; state->masks[1] &= ~state->planes[planes + i]; } /* Prepare the flags and pixel values for each color. */ for (i = 0; i < (1 << planes); i++) { colors[i].pixel = color(state, i | (i << planes)); colors[i].flags = DoRed | DoGreen | DoBlue; } /* Prepare the two color map settings. */ /* Colormap 0 displays the "low" planes. */ /* Colormap 1 displays the "high" planes. */ low_mask = (1 << planes) - 1; high_mask = low_mask << planes; for (i = state->map_size - 1; i >= 0; i--) { state->colormaps[0][i] = colors[i & low_mask]; state->colormaps[0][i].pixel = color(state, i); state->colormaps[1][i] = colors[(i & high_mask) >> planes]; state->colormaps[1][i].pixel = color(state, i); } /* Set up initial color map and write_enable. */ state->buffer = 0; state->drawing_planes = state->masks[state->buffer]; XStoreColors(state->display, state->cmap, state->colormaps[state->buffer], state->map_size); return(state); } void double_buffer_switch(state) register double_buffer_state *state; /* * Change double buffering buffer. * Return the new planes mask for double buffering. */ { /* Toggle the buffers. */ state->buffer ^= 1; /* Adjust the color map and write enable mask. */ XStoreColors(state->display, state->cmap, state->colormaps[state->buffer], state->map_size); state->drawing_planes = state->masks[state->buffer]; } void end_double_buffer(state) register double_buffer_state *state; { XFreeColors(state->display, state->cmap, &state->pixel, 1, ~(state->masks[0] & state->masks[1])); release(state); } @EOF chmod 664 double_buf.c echo x - double_buf.h cat >double_buf.h <<'@EOF' /* * double_buf.h - declarations for an Xlib double buffering utility. */ /* double buffering state record */ typedef struct { Display *display; Colormap cmap; long drawing_planes; /* planes currently drawn to */ int buffer; /* which buffer to show, even or odd */ XColor *colormaps[2]; /* color maps for even and odd buffers */ int map_size; /* number of entries in color maps */ long masks[2]; /* write_enable masks for odd and even */ long *planes; /* individual planes */ long pixel; /* pixel base value of double buffering */ } double_buffer_state; /* double buffering procedures */ extern double_buffer_state *start_double_buffer(); extern void double_buffer_switch(); extern void end_double_buffer(); @EOF chmod 664 double_buf.h exit 0