/*
 * 	xv_x_color.c
 *    This program demonstrates the combined use of the XView color
 *    model/API and Xlib graphics calls. The program uses XView to 
 *    create and manage its colormap segment while doing its actual 
 *    drawing using Xlib. The program draws the X logo in red, green
 *    and blue.
 */
#include <X11/Xlib.h>
#include <X11/bitmaps/xlogo64>
#include <xview/xview.h>
#include <xview/canvas.h>
#include <xview/cms.h>
#include <xview/xv_xrect.h>

#define WIDTH                           448
#define HEIGHT                          192

/* Color definitions */
#define WHITE                           0
#define RED                             1
#define GREEN                           2
#define BLUE                            3
#define NUM_COLORS                              4

/* graphics context used for rendering logos */
GC      gc;

/* conversion table for pixel values from XView to X11 */
unsigned long     pixel_table[NUM_COLORS];

/*
 *              main()
 *    Create a frame and a canvas.
 *    Allocate read-only colors (called a static colormap segment in
 *    XView parlance) and associate colors with the canvas.
 *    The indices into an XView colormap segment always range from 0 to
 *    size-1, where size is the number of colors allocated in the
 *    colormap segment. These logical index values translate into actual 
 *    indices into the colormap map as allocated by the X server. The
 *    CMS_INDEX_TABLE attribute returns the actual colormap indices. 
 *    The indices are returned as an array of unsigned long.
 */
main(argc,argv)
    int         argc;
    char                *argv[];
{
	Frame   	frame;
	Canvas         	canvas;
	Cms		cms;
	Xv_Singlecolor  cms_colors[NUM_COLORS];
	Display        	*display;
	XGCValues      	gc_val;
	XID            	xid;
	Pixmap         	xlogo;
	XGCValues      	gcvalues;
	int            	gcvaluemask;
	unsigned long	*xpixels;
	void           	canvas_repaint_proc();
	register int   	i;

	xv_init(XV_INIT_ARGS, argc, argv, 0);

	frame = xv_create(XV_NULL, FRAME,
			  FRAME_LABEL,                  "xv_color",
			  XV_WIDTH,                     WIDTH,
			  XV_HEIGHT,                    HEIGHT,
			  0);

	/* Initialize required colors */
	initialize_cms_colors(cms_colors);

	cms = xv_create(XV_NULL, CMS,
			CMS_SIZE, NUM_COLORS,
			CMS_COLORS, cms_colors,
			0);

	/* Get the actual indices into the colormap and store */
	xpixels = (unsigned long *)xv_get(cms, CMS_INDEX_TABLE);
	for (i = 0; i <= NUM_COLORS; i++) {
	    pixel_table[i] = xpixels[i];
	}

	canvas = xv_create(frame, CANVAS,
			   CANVAS_X_PAINT_WINDOW,   TRUE,
			   CANVAS_REPAINT_PROC,
			   canvas_repaint_proc,
			   WIN_CMS, cms,
			   0);

	/* Get display and the XID of the canvas */
	display = (Display *)xv_get(canvas, XV_DISPLAY);
	xid = (XID)xv_get(canvas, XV_XID);

	/* create the stipple xlogo */
	xlogo = XCreateBitmapFromData(display, xid, (char *)xlogo64_bits,
				      xlogo64_width, xlogo64_height);
	if( xlogo == NULL ) {
		printf( "Error allocating Pixmap for logo!\n");
		exit(1);
	}

	/* setup gc for rendering logos to screen */
	gcvalues.function = GXcopy;
	gcvalues.stipple = xlogo;
	gcvalues.fill_style = FillStippled;
	gcvalues.graphics_exposures = False;
	gcvaluemask = GCFunction | GCStipple | GCFillStyle |
	GCGraphicsExposures;

	/* create normal render gc for logo rendering */
	gc = XCreateGC(display, xid, gcvaluemask, &gcvalues);
	if(gc == NULL) {
		printf("Error allocating render graphics context!\n");
		exit(1);
	}

	/* Start event loop */
	xv_main_loop(frame);
	return(0);
}


/*
 *              canvas_repaint_proc()
 *      Draws onto the canvas using Xlib drawing functions.
 *      Use the current clipping rectangle to
 *      1. Restrict graphics output by setting the clip_mask
 *         in the graphics context.
 *      2. Do "smart repainting" by only painting the objects
 *         that lie within the damaged region (not being done in
 *         this example).
 */
void
canvas_repaint_proc(canvas, pw, display, xid, xrects)
    Canvas      canvas;
    Xv_Window   pw;
    Display     *display;
    Window      xid;
    Xv_xrectlist *xrects;
{
	XGCValues                               gc_val;
	unsigned long                   pixel_value;

	/* Set clip rects, if any */
	if (xrects) {
		XSetClipRectangles(display, gc, 0, 0,
		xrects->rect_array,
				   xrects->count, Unsorted);
	} else {
		gc_val.clip_mask = None;
		XChangeGC(display, gc, GCClipMask, &gc_val);
	}

	/* draw the logos in red, green and blue */
	pixel_value = (long)pixel_table[RED];
	XSetForeground(display, gc, pixel_value);
	XFillRectangle(display, xid, gc, 64, 64, xlogo64_width,
	xlogo64_height);

	pixel_value = (long)pixel_table[GREEN];
	XSetForeground(display, gc, pixel_value);
	XFillRectangle(display, xid, gc, 192, 64, xlogo64_width,
	xlogo64_height);

	pixel_value = (long)pixel_table[BLUE];
	XSetForeground(display, gc, pixel_value);
	XFillRectangle(display, xid, gc, 320, 64, xlogo64_width,
	xlogo64_height);
}

initialize_cms_colors(colors)
    Xv_Singlecolor      *colors;
{
    colors[WHITE].red = 255;
    colors[WHITE].green = 255;
    colors[WHITE].blue = 255;
 
    colors[RED].red = 255;
    colors[RED].green = 0;
    colors[RED].blue = 0;
 
    colors[GREEN].red = 0;
    colors[GREEN].green = 255;
    colors[GREEN].blue = 0;
 
    colors[BLUE].red = 0;
    colors[BLUE].green = 0;
    colors[BLUE].blue = 255;
}
