/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
/* |                                                                   | */
/* | Permission to use, copy, modify, and to distribute this software  | */
/* | and its documentation for any purpose is hereby granted without   | */
/* | fee, provided that the above copyright notice appear in all       | */
/* | copies and that both that copyright notice and this permission    | */
/* | notice appear in supporting documentation.  There is no           | */
/* | representations about the suitability of this software for        | */
/* | any purpose.  this software is provided "as is" without express   | */
/* | or implied warranty.                                              | */
/* |                                                                   | */
/* +-------------------------------------------------------------------+ */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Label.h>
#include <ctype.h>

#include "bitmaps/background.xbm"

#ifndef XtNcursor
#define XtNcursor	 "cursor"
#endif

#include "xpaint.h"

Widget GetToplevel(Widget w)
{
	Widget	p = w;

	while (w != None) {
		p = w;
		w = XtParent(w);
	}
	return p;
}

Widget GetShell(Widget w)
{
	while (!XtIsShell(w))
		w = XtParent(w);
	return w;
}

void SetIBeamCursor(Widget w)
{
	XtVaSetValues(w, XtVaTypedArg, 
		XtNcursor, XtRString, "xterm", sizeof(Cursor), NULL);
}

void SetCrossHairCursor(Widget w)
{
	XtVaSetValues(w, XtVaTypedArg, 
		XtNcursor, XtRString, "crosshair", sizeof(Cursor), NULL);
}
void SetPencilCursor(Widget w)
{
	XtVaSetValues(w, XtVaTypedArg, 
		XtNcursor, XtRString, "pencil", sizeof(Cursor), NULL);
}

/*
**  Some useful XRectangle computation code.
*/
XRectangle *RectUnion(XRectangle *a, XRectangle *b)
{
	static XRectangle	out;
	int			sx, ex, sy, ey;

	sx = MIN(a->x, b->x);
	sy = MIN(a->y, b->y);
	ex = MAX(a->x + a->width,  b->x + b->width);
	ey = MAX(a->y + a->height, b->y + b->height);
	
	XYtoRECT(sx, sy, ex, ey, &out);
	
	return &out;
}

XRectangle *RectIntersect(XRectangle *a, XRectangle *b)
{
	static XRectangle	out;
	int			w, h;

	if (a == NULL || b == NULL)
		return NULL;
 
	out.x = MAX(a->x, b->x);
	out.y = MAX(a->y, b->y);
	w     = MIN(a->x + a->width,  b->x + b->width)  - out.x;
	h     = MIN(a->y + a->height, b->y + b->height) - out.y;

	if (w <= 0 || h <= 0)
		return NULL;

	out.width  = w;
	out.height = h;

	return &out;
}

/*
**
*/
void GetPixmapWHD(Display *dpy, Drawable d, int *wth, int *hth, int *dth)
{
	Window		root;
	int		x, y;
	unsigned int	width, height, bw, depth;

	XGetGeometry(dpy, d, &root, &x, &y, &width, &height, &bw, &depth);

	if (wth != NULL) *wth = width;
	if (hth != NULL) *hth = height;
	if (dth != NULL) *dth = depth;
}

/*
**  Two useful functions to "cache" both a tiled background
**    and a Xor gc
*/
typedef struct bgList_s {
	int			depth;
	Pixmap			pixmap;
	struct	bgList_s	*next;
} BackgroundList;

static BackgroundList	*bgList = NULL;

Pixmap	GetBackgroundPixmap(Widget w)
{
	Widget		p, n;
	Display		*dpy = XtDisplay(w);
	int		depth;
	Pixmap		pix;
	Pixel		fg, bg;
	BackgroundList	*cur;
	Widget		tw;

	for (n = XtParent(p=w); !XtIsShell(n); n = XtParent(p=n));

	XtVaGetValues(p, XtNdepth, &depth, NULL);

	for (cur = bgList; bgList != NULL; bgList = bgList->next)
		if (cur->depth == depth)
			return cur->pixmap;

	tw = XtVaCreateWidget("junkWidget", labelWidgetClass, w, 
				XtNwidth, 1, 
				XtNheight, 1, 
				NULL);
	XtVaGetValues(tw, XtNforeground, &fg, 
	                  XtNbackground, &bg, 
			  NULL);

	XtDestroyWidget(tw);

	pix = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy),
				(char *)background_bits,
				background_width, background_height,
				bg,fg, depth);

	cur = XtNew(BackgroundList);
	cur->next = bgList;
	bgList = cur;
	cur->depth = depth;
	cur->pixmap = pix;
	return pix;
}

typedef struct gcList_s {
	Widget			widget;
	int			depth;
	GC			gc;
	struct	gcList_s	*next;
} GCXList;

static GCXList	*gcList = NULL;

GC	GetGCX(Widget w)
{
	Widget		n = GetShell(w);
	int		depth;
	GCXList		*cur;
	XGCValues	values;

	XtVaGetValues(n, XtNdepth, &depth, NULL);

	for (cur = gcList; gcList != NULL; gcList = gcList->next)
		if (cur->depth == depth)
			return cur->gc;

	values.function   = GXxor;
	values.foreground = ~0;

	cur = XtNew(GCXList);
	cur->next = gcList;
	gcList = cur;
	cur->depth = depth;
	cur->gc = XtGetGC(n, GCFunction|GCForeground, &values);
	return cur->gc;
}

/*
**  Argv parsing routines
*/

static char	*nextArg(char *str, char **start)
{
	char	*cp;
	int	flg;

	while (isspace(*str))
		str++;
	if (start != NULL)
		*start = str;
	if (*str == '\0')
		return NULL;
	if (*str == '\'' || *str == '"') {
		char	delim = *str;
		if (start != NULL)
			(*start)++;
		cp = ++str;
		while (*str != '\0' && *str != delim) {
			if (*str == '\\') {
				if (*++str == '\0')
					continue;
			}
			*cp++ = *str++;
		}
		*cp = '\0';
	} else {
		while (!isspace(*str) && *str != '\0')
			str++;
	}

	flg = (*str != '\0');
	*str = '\0';
	return str + (flg ? 1 : 0);
}

void	StrToArgv(char *str, int *argc, char **argv)
{
	int	t;
	char	*cp;

	if (argc == NULL)
		argc = &t;

	*argc = 0;
	for (cp = str; cp != NULL; (*argc)++)
		cp = nextArg(cp, argv == NULL ? NULL : &argv[*argc]);

	if (argv != NULL)
		argv[--(*argc)] = NULL;
}

/*
**  Create a XImage
*/
XImage	*NewXImage(Display *dpy, Visual *visual, int depth, int width, int height)
{
	XImage	*xim;
	int	pad;

	if (depth > 16)
		pad = 32;
	else if (depth > 8)
		pad = 16;
	else
		pad = 8;

	xim = XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL, width, height, pad, 0);	

	if (xim == NULL)
		return NULL;

	xim->data = (char*)XtMalloc(xim->bytes_per_line * height);

	if (xim->data == NULL) {
		XDestroyImage(xim);
		xim = NULL;
	}

	return xim;
}
