/* 
	Adapted from Examples in the book
	"X Window : Application Programming"
	by Eric F. Johnson and Kevin Reichard
---------
sumant
*/
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>

#include <math.h>
#include "preview.h"

#define BORDER_WIDTH 	2
static	Window		theWindow;
static	Display		*theDisplay;
static	int		theScreen;
static  int		theDepth;
static	unsigned int	theHeight, theWidth;
static  unsigned long	theBlackPixel;
static  unsigned long	theWhitePixel;

static	GC		theGC;

#define	CMAPSIZE	256
static	unsigned long	carray[CMAPSIZE];
static	Colormap	theColormap;


initX(x,y,width,height)
int x,y,width,height; /* Window Sizes */
{
	XSetWindowAttributes    theWindowAttributes;
	XWMHints		theWMHints;
        XSizeHints              theSizeHints;
        unsigned long           theWindowMask=CWBackPixel|CWBorderPixel|CWEventMask|CWSaveUnder;
	XGCValues		theGCValues;
	char			*theArguments[2];
	int			errorHandler();
	XEvent                  event;

	if ((theDisplay = XOpenDisplay(NULL)) == NULL) {
		fprintf(stderr," init: cannot open display %s.\n",
			XDisplayName(NULL));
		exit(1);
	}
	theScreen = DefaultScreen(theDisplay);
	theDepth = DefaultDepth(theDisplay, theScreen);
	theColormap = DefaultColormap(theDisplay, theScreen);
	theWhitePixel = WhitePixel(theDisplay,theScreen);
	theBlackPixel = BlackPixel(theDisplay,theScreen);

	if (theDepth == 1) {
		int i;
		carray[0] = theBlackPixel;
		for (i = 1; i < CMAPSIZE; i++)
			carray[i] = theWhitePixel;
	} else {
		mapcolor(0,"black");
		mapcolor(1, "red");
		mapcolor(2, "green");
		mapcolor(3, "yellow");
		mapcolor(4, "blue");
		mapcolor(5, "magenta");
		mapcolor(6, "cyan");
		mapcolor(7, "white");
	}

	theWindowAttributes.border_pixel = theWhitePixel;
	theWindowAttributes.background_pixel = theBlackPixel;
	theWindowAttributes.event_mask = StructureNotifyMask;
	theWindowAttributes.save_under = True;
	theWindow=XCreateWindow(theDisplay,
		  RootWindow(theDisplay,theScreen),
		  x,y,width,height,
		  BORDER_WIDTH,
		  theDepth,
		  InputOutput,
		  CopyFromParent,
		  theWindowMask,
		  &theWindowAttributes);
        theSizeHints.flags = PPosition|PSize;
        theSizeHints.x = x;
        theSizeHints.y = y;
        theSizeHints.width = width;
        theSizeHints.height = height;
        XSetNormalHints(theDisplay, theWindow, &theSizeHints);
	if ((theGC = XCreateGC(theDisplay,theWindow,(unsigned long)0,&theGCValues))==0){
		fprintf(stderr,"Cannot Create the Graphic Context.\n");
		XDestroyWindow(theDisplay,theWindow);
		exit(0);
	}
	XSetBackground(theDisplay, theGC,theBlackPixel);
	XSetForeground(theDisplay, theGC,theWhitePixel);
	
	XMapWindow(theDisplay,theWindow); XFlush(theDisplay);
        /*
         * Wait for Exposure event.
         */
        do {
                XNextEvent(theDisplay, &event); 
        } while (event.type != MapNotify);
	XSelectInput(theDisplay,theWindow,ExposureMask);


	XSetErrorHandler(errorHandler);
}

deinitX()
{
	XFreeGC(theDisplay, theGC);

	XUnmapWindow(theDisplay, theWindow);
	XDestroyWindow(theDisplay, theWindow);
	XCloseDisplay(theDisplay);
}

int errorHandler(theDisplay,theErrorEvent)
Display *theDisplay;
XErrorEvent *theErrorEvent;
{
	int bufferlength = 120;
	char theBuffer[121];

	XGetErrorText(theDisplay,theErrorEvent->error_code,theBuffer,bufferlength);
	fprintf(stderr,"X Error : %s\n",theBuffer);
	fprintf(stderr,
		"\tSerial Number of request : %ld\n\tOp Code : %d.%d\n\tError Code : %d\n",
		theErrorEvent->serial,theErrorEvent->request_code,
		theErrorEvent->minor_code,theErrorEvent->error_code);
	fprintf(stderr,
		"\tResource ID of failed request : %ld on display %s.\n",
		theErrorEvent->resourceid,
		DisplayString(theDisplay));
}

Xdraw(x, y,x1,y1)
int	x, y;
int	x1, y1;
{
	XDrawLine(theDisplay, theWindow, theGC, x, y, x1,y1);

	XFlush(theDisplay);
}

clear(from_x,from_y,size_x,size_y)
int from_x,from_y,size_x,size_y;
{
	XFillRectangle(theDisplay,
		theWindow,
		theGC,
		from_x,
		from_y, 
		size_x,
		size_y
	);
	XFlush(theDisplay);
}

color(ind)
int	ind;
{
	XSetForeground(theDisplay, theGC,  carray[ind]);
	XFlush(theDisplay);
}

mapcolor(i,cs)
int	i;
char 	*cs;
{
	XColor	c,hc;
	if (XLookupColor(theDisplay,theColormap,cs,&c,&hc) !=0){
		if ( XAllocColor(theDisplay, theColormap, &hc) == 0) {
			fprintf(stderr, "XAllocColor failed.\n");
			exit(1);
		}
		carray[i] = hc.pixel;
	}
	else fprintf(stderr, "XLookupColor for %s failed.\n",cs);
}

setcolor(i,r,g,b)
int i;
float r,g,b;
{
	if (theDepth == 1)
		carray[i]=theWhitePixel;
	else {
		XColor xcolor;
        
		/* Gamma Correct with 2.5 Gamma. */
		r = (float)pow((double)r,(double)0.4);
		g = (float)pow((double)g,(double)0.4);
		b = (float)pow((double)b,(double)0.4);

                xcolor.red = r*65535;
                xcolor.green=g*65535;
                xcolor.blue= b*65535;
                xcolor.flags=DoRed|DoGreen|DoBlue;
                if (XAllocColor(theDisplay, theColormap,&xcolor)==0){
                        fprintf(stderr, "XAllocColor failed.\n");
                        exit(1);
                }
                carray[i] = xcolor.pixel;
	}
}
int window_exposed()
{
	XEvent theEvent;
	int flag = 0;
	/*
	int nevents=XPending(theDisplay);
	if (nevents > 0){
	XNextEvent(theDisplay,&theEvent);
	return((theEvent.type==Expose)?1:0);
	}
	return(flag);
	*/
	flag = XCheckMaskEvent(theDisplay,ExposureMask,&theEvent);
	return(flag);
}
