/* $Id: Icon.c,v 1.1 1997/04/15 10:09:35 archer Exp $
 *	ICON.C - Icon allocator
 *
 * Support for mono-chrome, color pixmaps, and programmatic icons
 */
#include <Widget/WidgetsP.h>
#include <Widget/IconP.h>
#ifdef HAVE_LIBXPM
#include <X11/xpm.h>
#endif
#include <ctype.h>


/**
 ** Pixmaps from icons
 **/
#include "pixmap/xm_error"
#include "pixmap/xm_information"
#include "pixmap/xm_question"
#include "pixmap/xm_warning"


/**
 ** Public icons
 **/
X11_icon	X11_IconFatalError = X11_IconMono(xm_error_width,
						xm_error_height,
						xm_error_bits),
		X11_IconError = X11_IconMono(xm_information_width,
						xm_information_height,
						xm_information_bits),
		X11_IconWarning = X11_IconMono(xm_warning_width,
						xm_warning_height,
						xm_warning_bits),
		X11_IconQuestion = X11_IconMono(xm_question_width,
						xm_question_height,
						xm_question_bits);


/**
 ** Private variables
 **/
#ifdef HAVE_LIBXPM
static XpmAttributes	xpm_attr;
#endif
static GC		icon_gc, clip_gc, xor_gc;

 
/**
 ** X11_ICON_SIZED
 **	Make sure an icon has a size
 **	(used for .xpm icons, whose size isn't known beforehand)
 **/
void x11__icon_sized(X11_icon *icon)
{
char	*s;
/*
 * Already done
 */
	if (icon->w && icon->h)
		return;
/*
 * Cant!
 */
	if (!icon->xpm_data)
		return;
/*
 * Decode xpm
 */
	s = icon->xpm_data[0];
	while (isspace(*s))
		s++;
	icon->w = atoi(s);
	while (*s)
		if (isspace(*s++))
			break;
	while (isspace(*s))
		s++;
	icon->h = atoi(s);
}


/**
 ** Internal: REVERSE
 **	Toggle all pixels 1 into 0, and vice-versa
 **/
static void reverse(Pixmap m, unsigned int w, unsigned int h)
{
XGCValues	v;
/*
 * Special GC for bitmaps?
 */
	if (!xor_gc) {
		v.graphics_exposures = False;
		v.foreground         = 1;
		v.function           = GXxor;
		xor_gc = XCreateGC(x11__screen, m,
			GCGraphicsExposures|GCFunction|GCForeground, &v);
	}
/*
 * Switch
 */
	XFillRectangle(x11__screen, m, xor_gc, 0, 0, w, h);
}


/**
 ** X11_COLOR_PIXMAP
 **	Return the pixmap associated with the colored part of an Icon
 **/
Pixmap x11__color_pixmap(X11_icon *icon)
{
/*
 * Job already done?
 */
	if (icon->color_pixmap)
		return icon->color_pixmap;
#ifdef HAVE_LIBXPM
	if (!icon->xpm_data)
		return None;
/*
 * Create Pixmap using XPM
 */
	XpmCreatePixmapFromData(x11__screen, x11__root_id, icon->xpm_data,
			&icon->color_pixmap, &icon->mask_pixmap, &xpm_attr);
/*
 * If there's a mono-mask, then we're gonna use a reversed mask
 */
	if (icon->mask_pixmap)
		reverse(icon->mask_pixmap, icon->w, icon->h);
/*
 * Done
 */
	return icon->color_pixmap;
#else
	return None;
#endif
}


/**
 ** X11_DATA_BITMAP
 **	Return the bitmap associated with the data part of an Icon
 **/
Pixmap x11__data_bitmap(X11_icon *icon)
{
/*
 * Allocate if not already done
 */
	if (!icon->data_pixmap)
		icon->data_pixmap = XCreateBitmapFromData(x11__screen,
							  x11__root_id,
							  icon->mono_data,
							  icon->w, icon->h);
/*
 * Return pixmap
 */
	return icon->data_pixmap;
}


/**
 ** X11_ICON_DRAW
 **	Draw an icon over a window
 **/
void x11__icon_draw(Window id, X11_icon *icon, unsigned long bk,
			unsigned long fg, int x, int y)
{
Pixmap	draw;
/*
 * Need a GC
 */
	if (!icon_gc)
		x11__icon_init();
	x11__icon_sized(icon);
/*
 * Model 0 icon: Function called back to draw!
 */
	if (icon->on_redraw) {
/*** HACK ***/
		(*icon->on_redraw)(0);
		return;
	}
/*
 * Model 1 icon: Color with variable background
 */
#ifdef HAVE_LIBXPM
	if (!x11__is_monochrome) {
		if (x11__color_pixmap(icon) && icon->mask_pixmap) {
			XSetStipple(x11__screen, clip_gc, icon->mask_pixmap);
			XSetForeground(x11__screen, clip_gc, bk);
			XFillRectangle(x11__screen, icon->color_pixmap, clip_gc,
						0, 0, icon->w, icon->h);
		}
/*
 * Model 2 icon: .xpm data
 */
		if (icon->color_pixmap) {
			XCopyArea(x11__screen, icon->color_pixmap, id, icon_gc,
						0, 0, icon->w, icon->h, x, y);
			return;
		}
	}
#endif /*HAVE_LIBXPM*/
/*
 * Model 3 icon: Monochrome bitmap
 */
	if (icon->mono_data) {
		draw = x11__data_bitmap(icon);
		XSetForeground(x11__screen, icon_gc, fg);
		XSetBackground(x11__screen, icon_gc, bk);
		XCopyPlane(x11__screen, x11__data_bitmap(icon), id, icon_gc,
				0, 0, icon->w, icon->h, x, y, 0x1);
		return;
	}
/*
 * Model 4 icon: Black & White over a variable background
 */
/*** HACK ***/
/*
 * Model 5 icon: void icon
 */
	XSetForeground(x11__screen, icon_gc, fg);
	XDrawRectangle(x11__screen, id, icon_gc, x, y, icon->w-1, icon->h-1);
}


/**
 ** X11_ICON_USED
 **	Increment the reference count of an Icon
 **/
void X11_IconUsed(X11_icon *i)
{
	if (i)
		i->referenced++;
}


/**
 ** X11_ICON_RELEASED
 **	Decrement the reference count of an Icon
 **/
void X11_IconRelease(X11_icon *i)
{
	if (i && i->referenced) {
		i->referenced--;
	}
}


/**
 ** X11_ICON_INIT
 **	Initialize icon support
 **/
void x11__icon_init(void)
{
XGCValues	v;
/*
 * Values
 */
	v.graphics_exposures = False;
	icon_gc = XCreateGC(x11__screen, x11__root_id, GCGraphicsExposures, &v);
/*
 * Clip-GC is used with stipples
 */
	v.fill_style  = FillStippled;
	v.ts_x_origin = 0;
	v.ts_y_origin = 0;
	clip_gc = XCreateGC(x11__screen, x11__root_id,
			GCGraphicsExposures|GCFillStyle|GCTileStipXOrigin|
			GCTileStipYOrigin, &v);
}
