[comp.windows.x] XView, PixMaps, Canvas Repaint Proc

ralph@computing-maths.cardiff.ac.uk (Ralph Martin) (06/26/90)

I have a program (see below) which draws fractals. In the first version, I
basically set up a canvas paint window, and drew straight into it,
using notify_dispatch at the end of each row of pixels. All well and
good, except that there was no canvas repaint proc in case of damage.
So, in a second version, I create a Pixmap, and draw into that too, and
then copy areas of that to the paint window as a repaint proc. This
just does not seem to work. Furthermore, it also seems to screw up
something else, in that some sliders which used to appear in a panel no
longer appear at all. I am enclosing the program below, and I have
marked with /* NEW */ all added lines which are to do with the Pixmap.
Please note it needs a colour display. If you can tell me what I am
doing wrong, I'd be really grateful, or if you can give me some pointers
on how to do it right. The Xview Programming Manual and other Sun
documentation seem rather weak on this point!
Ralph
---------------------------------- cut here ----------------------------

#include <X11/Xlib.h>
#include <xview/xview.h>
#include <xview/panel.h>
#include <xview/canvas.h>
#include <xview/cms.h>
#include <xview/win_input.h>
#include <xview/xv_xrect.h>
#define A 512
#define A1 (A-1)
#define B 512
#define B1 (B-1)

/*
 * compile with cc -O4 pretty.c -f68881 -o pretty -lxview -lX11 -lm
 */

Frame           base_frame;
Panel           panel;
Panel_item      rslider, gslider, bslider, cslider, qbutton;
Canvas          canvas;
Xv_cmsdata      cms_data;
GC              gccanvas, gcpixmap; /* NEW */ /* gcpixmap only */
XGCValues       gc_val;
Display        *display;
Drawable        drawable;
Pixmap          thepixmap; /* NEW */
int             thecolour = 1;
int             value;
unsigned char   red[128], green[128], blue[128];
double          xmax, xmin, ymax, ymin;

main(argc, argv)
    int             argc;
    char          **argv;
{

    double          delta_x, delta_y;
    double          p, q;
    register double x, y, x_next, y_next, r, x0, y0;
    int             M, K;
    register int    nx, ny, k, i;

    void            sliderval(), csliderval(), quitproc(), repaintproc(), mouseproc(); /* NEW */ /* (repaintproc new only) */

    extern Notify_error notify_dispatch();

    xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);

    srand(getpid());
    for (i = 1; i < 127; i++) {
	red[i] = rand();
	blue[i] = rand();
	green[i] = rand();
    };
    red[0] = blue[0] = green[0] = 255;
    red[127] = blue[127] = green[127] = 0;

    cms_data.type = XV_DYNAMIC_CMS;
    cms_data.size = 128;
    cms_data.rgb_count = 128;
    cms_data.index = 0;
    cms_data.red = red;
    cms_data.green = green;
    cms_data.blue = blue;

    base_frame = xv_create(NULL, FRAME,
			   XV_LABEL, argv[0],
			   WIN_ERROR_MSG, "Cant open window.",
			   WIN_DYNAMIC_VISUAL, TRUE,
			   WIN_CMS_NAME, "Pretty",
			   WIN_CMS_DATA, &cms_data,
			   FRAME_INHERIT_COLORS, TRUE,
			   NULL);

    canvas = xv_create(base_frame, CANVAS,
		       XV_HEIGHT, A,
		       XV_WIDTH, B,
		       CANVAS_AUTO_SHRINK, FALSE,
		       CANVAS_AUTO_EXPAND, FALSE,
		       CANVAS_HEIGHT, A,
		       CANVAS_WIDTH, B,
		       CANVAS_RETAINED, TRUE,
		       CANVAS_X_PAINT_WINDOW, TRUE, /* NEW */
		       CANVAS_REPAINT_PROC, repaintproc, /* NEW */
		       WIN_DYNAMIC_VISUAL, TRUE,
		       WIN_CMS_NAME, "Pretty",
		       NULL);
    xv_set(canvas_paint_window(canvas),
	   WIN_CONSUME_EVENTS,
	   WIN_NO_EVENTS, MS_LEFT, NULL,
	   WIN_IGNORE_EVENT, WIN_UP_EVENTS,
	   WIN_EVENT_PROC, mouseproc,
	   NULL);

    panel = xv_create(base_frame, PANEL,
		      WIN_BELOW, canvas,
		      WIN_DYNAMIC_VISUAL, TRUE,
		      WIN_CMS_NAME, "Pretty",
		      WIN_X, 0,
		      NULL);

    rslider = xv_create(panel, PANEL_SLIDER,
			PANEL_LABEL_STRING, "Red:",
			PANEL_VALUE_X, 65,
			PANEL_MIN_VALUE, 0,
			PANEL_MAX_VALUE, 255,
			PANEL_SLIDER_WIDTH, 256,
			PANEL_NOTIFY_PROC, sliderval,
			PANEL_NOTIFY_LEVEL, PANEL_ALL,
			PANEL_VALUE, red[1],
			NULL);
    gslider = xv_create(panel, PANEL_SLIDER,
			PANEL_LABEL_STRING, "Green:",
			PANEL_VALUE_X, 65,
			PANEL_MIN_VALUE, 0,
			PANEL_MAX_VALUE, 255,
			PANEL_SLIDER_WIDTH, 256,
			PANEL_NOTIFY_PROC, sliderval,
			PANEL_NOTIFY_LEVEL, PANEL_ALL,
			PANEL_VALUE, green[1],
			NULL);
    bslider = xv_create(panel, PANEL_SLIDER,
			PANEL_LABEL_STRING, "Blue:",
			PANEL_VALUE_X, 65,
			PANEL_MIN_VALUE, 0,
			PANEL_MAX_VALUE, 255,
			PANEL_SLIDER_WIDTH, 256,
			PANEL_NOTIFY_PROC, sliderval,
			PANEL_NOTIFY_LEVEL, PANEL_ALL,
			PANEL_VALUE, blue[1],
			NULL);
    cslider = xv_create(panel, PANEL_SLIDER,
			PANEL_LABEL_STRING, "Colour:",
			PANEL_VALUE_X, 65,
			PANEL_MIN_VALUE, 1,
			PANEL_MAX_VALUE, 126,
			PANEL_VALUE, 1,
			PANEL_SLIDER_WIDTH, 252,
			PANEL_NOTIFY_PROC, csliderval,
			NULL);

    qbutton = xv_create(panel, PANEL_BUTTON,
			XV_X, 448,
			XV_Y, 45,
			PANEL_NOTIFY_PROC, quitproc,
			PANEL_LABEL_STRING, "Quit",
			NULL);

    window_fit(panel);
    window_fit(base_frame);
    xv_set(base_frame, XV_SHOW, TRUE, NULL);

    display = (Display *) xv_get(base_frame, XV_DISPLAY);
    drawable = (Drawable) xv_get(canvas_paint_window(canvas), XV_XID);

    thepixmap = XCreatePixmap(display, DefaultRootWindow(display), A, B, 8); /* NEW */

    gccanvas = XCreateGC(display, drawable, 0, NULL);
    gcpixmap = XCreateGC(display, thepixmap, 0, NULL); /* NEW */

    xv_set(base_frame,
	   FRAME_LEFT_FOOTER, "Calculating...",
	   FRAME_SHOW_FOOTER, TRUE, NULL);

    XSync(display, 1);
    notify_dispatch();

    xmin = -2.0;
    xmax = 2.0;
    ymin = -1.5;
    ymax = 1.5;
    delta_x = (xmax - xmin) / A1;
    delta_y = (ymax - ymin) / B1;
    M = 100;
    K = 128;
    p = 0.32;
    q = 0.043;
    y = ymin - delta_y;
    for (ny = 0; ny < B / 2; ny++) {
	y += delta_y;
	x = xmin - delta_x;
	for (nx = 0; nx < A; nx++) {
	    x += delta_x;

	    k = 0;

	    x0 = x;
	    y0 = y;

	    do {
		x_next = x0 * x0 - y0 * y0 + p;
		y_next = x0 * y0 + x0 * y0 + q;
		k++;

		r = x_next * x_next + y_next * y_next;
		x0 = x_next;
		y0 = y_next;
	    }
	    while (r <= M && k < K);

	    if (r > M)
		gc_val.foreground = k;
	    else
		gc_val.foreground = 128 - ((int) (r * 100)) % 128;
	    XChangeGC(display, gccanvas, GCForeground, &gc_val);
	    XChangeGC(display, gcpixmap, GCForeground, &gc_val); /* NEW */
	    /* Allow for y going top to bottom, symmetry */
	    XDrawPoint(display, drawable, gccanvas, nx, B1 - ny);
	    XDrawPoint(display, drawable, gccanvas, A1 - nx, ny);
	    XDrawPoint(display, thepixmap, gcpixmap, nx, B1 - ny); /* NEW */
	    XDrawPoint(display, thepixmap, gcpixmap, A1 - nx, ny); /* NEW */
	    /* colour pixel nx, ny is 0 */
	    notify_dispatch();
    }
    xv_set(base_frame, FRAME_LEFT_FOOTER, "Completed", 0);
    xv_main_loop(base_frame);
}

void
sliderval(item, value, event)
    Panel_item      item;
    int             value;
    Event          *event;

{
    if (item == rslider)
	red[thecolour] = value;
    else if (item == gslider)
	green[thecolour] = value;
    else if (item == bslider)
	blue[thecolour] = value;
    xv_set(base_frame, WIN_CMS_DATA, &cms_data, NULL);
}

csliderval(item, value, event)
    Panel_item      item;
    int             value;
    Event          *event;
{
    int             rval, gval, bval;

    thecolour = value;
    rval = red[thecolour];
    xv_set(rslider, PANEL_VALUE, rval, NULL);
    gval = green[thecolour];
    xv_set(gslider, PANEL_VALUE, gval, NULL);
    bval = blue[thecolour];
    xv_set(bslider, PANEL_VALUE, bval, NULL);
}

void
mouseproc(window, event)
    Xv_Window       window;
    Event          *event;

{
    char            msg[128];
    XImage         *image;
    int             x, y, colour, rval, bval, gval;
    double          realx, realy;

    if (event_left_is_down(event)) {
	x = event_x(event);
	y = event_y(event);
	image = XGetImage(display, drawable, x, y, 1, 1, AllPlanes, ZPixmap);
	thecolour = (int) XGetPixel(image, 0, 0);
	if (thecolour != 0) {
	    realx = xmin + (xmax - xmin) * x / A;
	    realy = ymax - (ymax - ymin) * y / B;
	    sprintf(msg, "Mouse click at %f, %f", realx, realy);
	    xv_set(base_frame, FRAME_RIGHT_FOOTER, msg, NULL);
	    xv_set(cslider, PANEL_VALUE, thecolour, NULL);
	    rval = red[thecolour];
	    xv_set(rslider, PANEL_VALUE, rval, NULL);
	    gval = green[thecolour];
	    xv_set(gslider, PANEL_VALUE, gval, NULL);
	    bval = blue[thecolour];
	    xv_set(bslider, PANEL_VALUE, bval, NULL);
	}
    }
}

void
quitproc(item, event)
    Panel_item      item;
    Event          *event;
{
    xv_destroy_safe(base_frame);
    exit(0);
}

repaintproc(canvas, paint_window, dpy, win, xrects) /* NEW */ /* all of it */
    Canvas          canvas;
    Xv_Window       paint_window;
    Display        *dpy;
    Window          win;
    Xv_xrectlist   *xrects;
{
    GC              gc;

    gc = XCreateGC(display, thepixmap, 0, NULL);
    for (xrects->count--; xrects->count >= 0; xrects->count--) {
	XCopyArea(dpy, thepixmap, xv_get(paint_window, XV_XID), gc,
		  xrects->rect_array[xrects->count].x,
		  xrects->rect_array[xrects->count].y,
		  xrects->rect_array[xrects->count].width,
		  xrects->rect_array[xrects->count].height,
		  xrects->rect_array[xrects->count].x,
		  xrects->rect_array[xrects->count].y);
    }
}
---------------------------------- end ----------------------------------