/**
 *
 * $Id: Visual.c,v 1.29 1999/09/03 00:17:41 rwscott Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static const char rcsid[] = "$Id: Visual.c,v 1.29 1999/09/03 00:17:41 rwscott Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>
#include <stdio.h>
#include <limits.h>

#include <Xm/XmP.h>
#include <Xm/PrimitiveP.h>
#include <Xm/ManagerP.h>
#include <Xm/ExtObjectP.h>
#include <Xm/GadgetP.h>

#include <XmI/DebugUtil.h>

#define	COLOR_CACHE_SIZE		5

#define	PCT_BRIGHTNESS			(6 * 0xffff / 100)

/* How much lighter/darker to make things in default routine */

#define	PCT_DARK_BOTTOM		70	/* lighter (less dark, actually) */
#define	PCT_DARK_TOP		50	/* lighter */
#define	PCT_LIGHT_BOTTOM	55	/* darker */
#define	PCT_LIGHT_TOP		80	/* darker */
#define	PCT_MEDIUM_BOTTOM_BASE	40	/* darker */
#define	PCT_MEDIUM_BOTTOM_RANGE	25
#define	PCT_MEDIUM_TOP_BASE	60	/* lighter */
#define	PCT_MEDIUM_TOP_RANGE	-30
#define	PCT_SELECT		85	/* darker (lighter if "dark") */

/* The "brightness" of an RGB color.  The "right" way seems to use
 * empirical values like the default thresholds below, but it boils down
 * to red is twice as bright as blue and green is thrice blue.
 */

#define	BRIGHTNESS(xc)		((xc).red + (xc).red + (xc).green + \
				 (xc).green + (xc).green + (xc).blue)

static Pixel black_or_white(XmColorData *cd, unsigned char which);
static void call_color_proc(XmColorData *cd);
static void _XmColorProcDefaultProc(XColor *bg_color, XColor *fg_color,
				    XColor *sel_color, XColor *ts_color,
				    XColor *bs_color);

static XContext background_color_context, background_spec_context;
static XmColorProc _color_proc = _XmColorProcDefaultProc;
static XmColorData color_cache[COLOR_CACHE_SIZE];

/*
 *  Note: 
 *  
 * At one time there was no cache in the color routines. When displaying
 * remotely, profile data indicated that the vast majority of the time
 * spent in _XtCreateWidget was spent getting colors from these routines.
 * In Aug 1997, Jon Christopher (jac8792@tamu.edu) added a cache to each
 * of these routines so that it will remember the data from the last call
 * and avoid server round trips if they are called again under the same
 * conditions.  These changes speeded up _XtCreateWidget by 10 times.
 *
 *  More recently (Sept 1998), Jamie Gritton (jamie@gritton.org) improved
 *  the cache by using the proper _Xm* routines as defined in XmP.h.
 *  Jamie has also implemented routines which use better default color
 *  calculations based on Motif-like empirical brightness calculations.
 *  Thanks, Jamie!  */


static void color_fail_warn(void)
{
  static int warned = False;
  
  if (!warned) {
    warned=True;
    _XmWarning(NULL,
	       "Cannot allocate colormap entry, some colors may be incorrect");
  }
}

XmColorProc
XmSetColorCalculation(XmColorProc proc)
{
    XmColorProc ret_val;

    ret_val = _color_proc;

    if (proc == NULL)
    {
	_color_proc = _XmColorProcDefaultProc;
    }
    else
    {
	_color_proc = proc;
    }

    _XmInvalidateColorCache( False);

    return ret_val;
}

XmColorProc
XmGetColorCalculation(void)
{
    return _color_proc;
}

void
_XmInvalidateColorCache(Boolean default_only)
{
    XmColorData *cc;

    if (!default_only || _color_proc == _XmColorProcDefaultProc)
	for (cc = color_cache; cc < color_cache + COLOR_CACHE_SIZE; cc++)
	    cc->allocated = 0;
}

/* Get a color cache entry */

XmColorData *
_XmGetColors(Screen *screen, Colormap color_map, Pixel background)
{
    XmColorData cd;
    XmColorData *cc;

    /* Construct a new blank record to possibly add */

    cd.allocated = 0;
    cd.screen = screen;
    cd.color_map = color_map;
    cd.background.pixel = background;
    cd.foreground.pixel =
	cd.top_shadow.pixel =
	cd.bottom_shadow.pixel =
	cd.select.pixel = 0;

    /* Get it from the cache, putting it in if necessary */

    cc = _XmAddToColorCache(&cd);

    /* Call the color proc if the entry is new */

    if (!(cc->allocated & XmBACKGROUND))
    {
	cc->allocated |= XmBACKGROUND;
	XQueryColor(DisplayOfScreen(screen),
		    color_map,
		    &cc->background);
	call_color_proc(cc);
    }

    return cc;
}

/* Get the colors for a widget with a default background */

XmColorData *
_XmGetDefaultColors(Screen *screen, Colormap color_map)
{
    Widget sw = XmGetXmScreen(screen);
    Colormap screen_color_map;
    XrmValue val;

    /* Get the background pixel */

    screen_color_map = CoreColormap(sw);
    CoreColormap(sw) = color_map;
    _XmBackgroundColorDefault(sw, 0, &val);
    CoreColormap(sw) = screen_color_map;

    /* _XmBackgroundColorDefault always leaves its mark
     * on the front of the color cache.
     */

    return color_cache;
}

/* Search the color cache for a matching entry */

Boolean
_XmSearchColorCache(unsigned int which, XmColorData *values,
		    XmColorData **ret)
{
    XmColorData *cc;

    for (cc = color_cache; cc < color_cache + COLOR_CACHE_SIZE; cc++)
	if (cc->allocated &&
	    (!(which & XmLOOK_AT_SCREEN) ||
	     cc->screen == values->screen) &&
	    (!(which & XmLOOK_AT_CMAP) ||
	     cc->color_map == values->color_map) &&
	    (!(which & XmLOOK_AT_BACKGROUND) ||
	     cc->background.pixel == values->background.pixel) &&
	    (!(which & XmLOOK_AT_FOREGROUND) ||
	     ((cc->allocated & XmFOREGROUND) &&
	      cc->foreground.pixel == values->foreground.pixel)) &&
	    (!(which & XmLOOK_AT_TOP_SHADOW) ||
	     ((cc->allocated & XmTOP_SHADOW) &&
	      cc->top_shadow.pixel == values->top_shadow.pixel)) &&
	    (!(which & XmLOOK_AT_BOTTOM_SHADOW) ||
	     ((cc->allocated & XmBOTTOM_SHADOW) &&
	      cc->bottom_shadow.pixel == values->bottom_shadow.pixel)) &&
	    (!(which & XmLOOK_AT_SELECT) ||
	     ((cc->allocated & XmSELECT) &&
	      cc->select.pixel == values->select.pixel)))
	{
	    /* Found the entry.  Bump it to the front of the cache
	     * to find it quicker next time, and to make this an LRU cache.
	     * Kind of expensive perhaps, but for a small cache that's fine.
	     */

	    if (cc > color_cache)
	    {
		XmColorData temp_cd = *cc;
		memmove(color_cache + 1, color_cache,
			(char *)cc - (char *)color_cache);
		*color_cache = temp_cd;
	    }
	    *ret = color_cache;
	    return True;
	}

    *ret = NULL;
    return False;
}

/* Parse/Allocate a background color and add it to the color cache */

void
_XmAddBackgroundToColorCache(Screen *screen, Colormap color_map,
			     String background_spec,
			     int rgb_fallback, XrmValue *val)
{
    XmColorData	cd;
    XmColorData *cc;
    static Pixel background;

    val->size = sizeof background;
    val->addr = (XPointer)&background;

    /* Parse the color.  If that fails, use the fallback RGB values */

    if (!XParseColor(DisplayOfScreen(screen), color_map, background_spec,
		     &cd.background))
    {
	_XmWarning(NULL, "Couldn't parse default background color - using fallback RGB values");
	cd.background.red =
	    (rgb_fallback >> 16 & 0xff) | (rgb_fallback >> 8 & 0xff00);
	cd.background.green =
	    (rgb_fallback >> 8 & 0xff) | (rgb_fallback & 0xff00);
	cd.background.blue =
	    (rgb_fallback & 0xff) | (rgb_fallback << 8 & 0xff00);
    }

    /* See if the color is in the cache.  This is like _XmSearchColorCache
     * except that it looks for background RGB values instead of pixels.
     */

    for (cc = color_cache; cc < color_cache + COLOR_CACHE_SIZE; cc++)
	if ((cc->allocated & XmBACKGROUND) &&
	    cc->screen == screen &&
	    cc->color_map == color_map &&
	    cc->background.red == cd.background.red &&
	    cc->background.green == cd.background.green &&
	    cc->background.blue == cd.background.blue)
	{
	    /* Found the entry.  Put in front like _XmSearchColorCache. */

	    if (cc > color_cache)
	    {
		cd = *cc;
		memmove(color_cache + 1, color_cache,
			(char *)cc - (char *)color_cache);
		*color_cache = cd;
	    }

	    /* It's already in the cache, so we're done */

	    background = color_cache->background.pixel;
	    return;
	}

    /* It's not in the cache.
     * Allocate it and put it in there (a la _XmGetColors).
     */

    if (!XAllocColor(DisplayOfScreen(screen), color_map, &cd.background))
    {
	DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmAddBackgroundToColorCache(%d) - Could not allocate color\n",
			   __FILE__,__LINE__));
	color_fail_warn();
	cd.background.pixel =
	    _XmWhitePixel(screen, color_map, cd.background);
	cd.background.red = cd.background.green = cd.background.blue =
	    0xffff;
    }
    cd.screen = screen;
    cd.color_map = color_map;
    cd.allocated = XmBACKGROUND;
    cd.foreground.pixel =
	cd.top_shadow.pixel =
	cd.bottom_shadow.pixel =
	cd.select.pixel = 0;
    call_color_proc(_XmAddToColorCache(&cd));
    background = cd.background.pixel;
}

/* Add an entry to the color cache, or augment an existing entry */

XmColorData *
_XmAddToColorCache(XmColorData *new_rec)
{
    XmColorData *cc;

    if (_XmSearchColorCache(XmLOOK_AT_SCREEN | XmLOOK_AT_CMAP |
			    XmLOOK_AT_BACKGROUND, new_rec, &cc))
    {
	/* Entry exists - add new data */

	cc->allocated |= new_rec->allocated;
	if (new_rec->allocated & XmBACKGROUND)
	{
	    cc->background = new_rec->background;
	}
	if (new_rec->allocated & XmFOREGROUND)
	{
	    cc->foreground = new_rec->foreground;
	}
	if (new_rec->allocated & XmTOP_SHADOW)
	{
	    cc->top_shadow = new_rec->top_shadow;
	}
	if (new_rec->allocated & XmBOTTOM_SHADOW)
	{
	    cc->bottom_shadow = new_rec->bottom_shadow;
	}
	if (new_rec->allocated & XmSELECT)
	{
	    cc->select = new_rec->select;
	}
	return cc;
    }
    else
    {
	/* Key doesn't exist - add the entire entry */

	memmove(color_cache + 1, color_cache,
		(COLOR_CACHE_SIZE - 1) * sizeof( XmColorData));
	color_cache[0] = *new_rec;
	return color_cache;
    }
}

/* Get a field from a color cache entry, allocating it if necessary */

Pixel
_XmAccessColorData(XmColorData *cd, unsigned char which)
{
    switch(which)
    {
    case XmBACKGROUND:
	return cd->background.pixel;
    case XmFOREGROUND:
	if (!(cd->allocated & XmFOREGROUND))
	{
	    cd->allocated |= XmFOREGROUND;
	    if (!XAllocColor(DisplayOfScreen(cd->screen),
			     cd->color_map,
			     &cd->foreground))
	    {
		DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmAccessColorData(%d) - Could not allocate XmFOREGROUND\n",
				   __FILE__,__LINE__));
		color_fail_warn();
		cd->foreground.pixel = black_or_white(cd, XmFOREGROUND);
	    }
	}
	return cd->foreground.pixel;
    case XmTOP_SHADOW:
	if (!(cd->allocated & XmTOP_SHADOW))
	{
	    cd->allocated |= XmTOP_SHADOW;
	    if (!XAllocColor(DisplayOfScreen(cd->screen),
			     cd->color_map,
			     &cd->top_shadow))
	    {
		DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmAccessColorData(%d) - Could not allocate XmTOP_SHADOW\n",
				   __FILE__,__LINE__));
		color_fail_warn();
		cd->top_shadow.pixel = black_or_white(cd, XmTOP_SHADOW);
	    }
	}
	return cd->top_shadow.pixel;
    case XmBOTTOM_SHADOW:
	if (!(cd->allocated & XmBOTTOM_SHADOW))
	{
	    cd->allocated |= XmBOTTOM_SHADOW;
	    if (!XAllocColor(DisplayOfScreen(cd->screen),
			     cd->color_map,
			     &cd->bottom_shadow))
	    {
		DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmAccessColorData(%d) - Could not allocate XmBOTTOM_SHADOW\n",
				   __FILE__,__LINE__));
		color_fail_warn();
		cd->bottom_shadow.pixel = black_or_white(cd, XmBOTTOM_SHADOW);
	    }
	}
	return cd->bottom_shadow.pixel;
    case XmSELECT:
	if (!(cd->allocated & XmSELECT))
	{
	    cd->allocated |= XmSELECT;
	    if (!XAllocColor(DisplayOfScreen(cd->screen),
			     cd->color_map,
			     &cd->select))
	    {
		DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmAccessColorData(%d) - Could not allocate XmSELECT\n",
				   __FILE__,__LINE__));
		color_fail_warn();
		cd->select.pixel = black_or_white(cd, XmSELECT);
	    }
	}
	return cd->select.pixel;
    }

    _XmWarning(NULL, "Invalid color specification in _XmAccessColorData");
    return 0;
}

/* If a color is unavailable, choose black or white */

static Pixel
black_or_white(XmColorData *cd, unsigned char which)
{
    int threshold = 0;
    long brightness;
    Widget sw;

    brightness = BRIGHTNESS( cd->background);
    sw = XmGetXmScreen(cd->screen);

    switch (which)
    {
    case XmFOREGROUND:
	threshold = Screen_ForegroundThreshold(sw)
	    ? Screen_ForegroundThreshold(sw) : XmDEFAULT_FOREGROUND_THRESHOLD;
	break;
    case XmTOP_SHADOW:
    case XmSELECT:
	threshold = Screen_LightThreshold(sw)
	    ? Screen_LightThreshold(sw) : XmDEFAULT_LIGHT_THRESHOLD;
	break;
    case XmBOTTOM_SHADOW:
	threshold = Screen_DarkThreshold(sw)
	    ? Screen_DarkThreshold(sw) : XmDEFAULT_DARK_THRESHOLD;
    }
    return brightness > threshold * PCT_BRIGHTNESS
	? _XmBlackPixel(cd->screen, cd->color_map, cd->select)
	: _XmWhitePixel(cd->screen, cd->color_map, cd->select);
}

/* Call the color proc to fill in color data */

static void call_color_proc(XmColorData *cd)
{
    if (DefaultDepthOfScreen(cd->screen) == 1)
    {
	/* Don't call the color proc for B/W screens.
	 * Just do an easy "bw proc".
	 */

	cd->allocated |=
	    XmFOREGROUND | XmTOP_SHADOW | XmBOTTOM_SHADOW | XmSELECT;
	if (cd->background.pixel == WhitePixelOfScreen(cd->screen))
	{
	    cd->foreground.red = cd->foreground.green =
		cd->foreground.blue = cd->bottom_shadow.red =
		cd->bottom_shadow.green = cd->bottom_shadow.blue =
		cd->select.red = cd->select.green = cd->select.blue = 0;
	    cd->foreground.pixel = cd->bottom_shadow.pixel =
		cd->select.pixel = BlackPixelOfScreen(cd->screen);
	    cd->top_shadow = cd->background;
	}
	else
	{
	    cd->foreground.red = cd->foreground.green =
		cd->foreground.blue = cd->top_shadow.red =
		cd->top_shadow.green = cd->top_shadow.blue =
		cd->select.red = cd->select.green = cd->select.blue =
		USHRT_MAX;
	    cd->foreground.pixel = cd->top_shadow.pixel =
		cd->select.pixel = WhitePixelOfScreen(cd->screen);
	    cd->bottom_shadow = cd->background;
	}
    }
    else
	_color_proc(&cd->background,
		    &cd->foreground,
		    &cd->select,
		    &cd->top_shadow,
		    &cd->bottom_shadow);
}

/* External entry point - get requested colors for a widget */

void
XmGetColors(Screen *screen,
	    Colormap color_map,
	    Pixel background,
	    Pixel *foreground_ret,
	    Pixel *top_shadow_ret,
	    Pixel *bottom_shadow_ret,
	    Pixel *select_ret)
{
    XmColorData *cd;

    cd = _XmGetColors( screen, color_map, background);

    if (foreground_ret)
	*foreground_ret = _XmAccessColorData( cd, XmFOREGROUND);
    if (top_shadow_ret)
	*top_shadow_ret = _XmAccessColorData( cd, XmTOP_SHADOW);
    if (bottom_shadow_ret)
	*bottom_shadow_ret = _XmAccessColorData( cd, XmBOTTOM_SHADOW);
    if (select_ret)
	*select_ret = _XmAccessColorData( cd, XmSELECT);
}

void
XmChangeColor(Widget widget,
	      Pixel background)
{
    Pixel foreground;
    Pixel top_shadow;
    Pixel bottom_shadow;
    Pixel select;

    XmGetColors(XtScreenOfObject(widget),
		ColormapOfObject(widget),
		background,
		&foreground,
		&top_shadow,
		&bottom_shadow,
		&select);

    XtVaSetValues(widget,
		  XmNbackground, background,
		  XmNforeground, foreground,
		  XmNhighlightColor, foreground,
		  XmNtopShadowColor, top_shadow,
		  XmNbottomShadowColor, bottom_shadow,
		  XmNarmColor, select,
		  XmNselectColor, select,
		  XmNtroughColor, select,
		  NULL);
}

/* the default color calculation */
static void
_XmColorProcDefaultProc(XColor *bg_color,
			XColor *fg_color,
			XColor *sel_color,
			XColor *ts_color,
			XColor *bs_color)
{
    int foreground_threshold, dark_threshold, light_threshold;
    long brightness, brightadj;
    XColor _widgetBackground;

    /* Find the thresholds for the different color models.
     * This is cheating - for these thresholds we need the Screen object,
     * which wasn't passed to this function.  Here's a hack:
     * If the background pointer is inside the color cache,
     * use that cache entry's screen.
     */

    if ((char *)bg_color > (char *)color_cache &&
	(char *)bg_color < (char *)(color_cache + COLOR_CACHE_SIZE))
    {
	Widget sw = XmGetXmScreen(color_cache[((char *)bg_color -
			(char *)color_cache) / sizeof(XmColorData)].screen);
	foreground_threshold = Screen_ForegroundThreshold(sw)
	    ? Screen_ForegroundThreshold(sw) : XmDEFAULT_FOREGROUND_THRESHOLD;
	dark_threshold = Screen_DarkThreshold(sw)
	    ? Screen_DarkThreshold(sw) : XmDEFAULT_DARK_THRESHOLD;
	light_threshold = Screen_LightThreshold(sw)
	    ? Screen_LightThreshold(sw) : XmDEFAULT_LIGHT_THRESHOLD;
    }
    else
    {
	foreground_threshold = XmDEFAULT_FOREGROUND_THRESHOLD;
	dark_threshold = XmDEFAULT_DARK_THRESHOLD;
	light_threshold = XmDEFAULT_LIGHT_THRESHOLD;
    }

    _widgetBackground = *bg_color;
    brightness = BRIGHTNESS(_widgetBackground);

    if (fg_color)
	fg_color->red = fg_color->green = fg_color->blue =
	    brightness > foreground_threshold * PCT_BRIGHTNESS ? 0 : 0xffff;

    /* For "dark" backgrounds, make everything a fixed %age lighter */

    if (brightness < dark_threshold * PCT_BRIGHTNESS)
    {
	if (sel_color)
	{
	    sel_color->red = 0xffff -
		((0xffff - _widgetBackground.red) * PCT_SELECT + 50) / 100;
	    sel_color->green = 0xffff -
		((0xffff - _widgetBackground.green) * PCT_SELECT + 50) / 100;
	    sel_color->blue = 0xffff -
		((0xffff - _widgetBackground.blue) * PCT_SELECT + 50) / 100;
	}
	if (ts_color)
	{
	    ts_color->red = 0xffff -
		((0xffff - _widgetBackground.red) * PCT_DARK_TOP + 50) / 100;
	    ts_color->green = 0xffff -
		((0xffff - _widgetBackground.green) * PCT_DARK_TOP + 50) / 100;
	    ts_color->blue = 0xffff -
		((0xffff - _widgetBackground.blue) * PCT_DARK_TOP + 50) / 100;
	}
	if (bs_color)
	{
	    bs_color->red = 0xffff -
		((0xffff - _widgetBackground.red) * PCT_DARK_BOTTOM) / 100;
	    bs_color->green = 0xffff - ((0xffff - _widgetBackground.green) *
					PCT_DARK_BOTTOM + 50) / 100;
	    bs_color->blue = 0xffff - ((0xffff - _widgetBackground.blue) *
				       PCT_DARK_BOTTOM + 50) / 100;
	}
    }

    /* For "light" background, make everything a fixed %age darker */

    else if (brightness > light_threshold * PCT_BRIGHTNESS)
    {
	if (sel_color)
	{
	    sel_color->red = (_widgetBackground.red * PCT_SELECT + 50) / 100;
	    sel_color->green =
		(_widgetBackground.green * PCT_SELECT + 50) / 100;
	    sel_color->blue = (_widgetBackground.blue * PCT_SELECT + 50) / 100;
	}
	if (ts_color)
	{
	    ts_color->red = (_widgetBackground.red * PCT_LIGHT_TOP + 50) / 100;
	    ts_color->green =
		(_widgetBackground.green * PCT_LIGHT_TOP + 50) / 100;
	    ts_color->blue =
		(_widgetBackground.blue * PCT_LIGHT_TOP + 50) / 100;
	}
	if (bs_color)
	{
	    bs_color->red =
		(_widgetBackground.red * PCT_LIGHT_BOTTOM + 50) / 100;
	    bs_color->green =
		(_widgetBackground.green * PCT_LIGHT_BOTTOM + 50) / 100;
	    bs_color->blue =
		(_widgetBackground.blue * PCT_LIGHT_BOTTOM + 50) / 100;
	}
    }

    /* For "medium" background, select is a fixed %age darker;
     * top (lighter) and bottom (darker) are a variable %age
     * based on the background's brightness
     */

    else
    {
	brightness = (brightness + (PCT_BRIGHTNESS >> 1)) / PCT_BRIGHTNESS;
	if (sel_color)
	{
	    sel_color->red = (_widgetBackground.red * PCT_SELECT + 50) / 100;
	    sel_color->green =
		(_widgetBackground.green * PCT_SELECT + 50) / 100;
	    sel_color->blue =
		(_widgetBackground.blue * PCT_SELECT + 50) / 100;
	}
	if (ts_color)
	{
	    brightadj = PCT_MEDIUM_TOP_BASE +
		(brightness * PCT_MEDIUM_TOP_RANGE + 50) / 100;
	    ts_color->red = 0xffff -
		((0xffff - _widgetBackground.red) * brightadj + 50) / 100;
	    ts_color->green = 0xffff -
		((0xffff - _widgetBackground.green) * brightadj + 50) / 100;
	    ts_color->blue = 0xffff -
		((0xffff - _widgetBackground.blue) * brightadj + 50) / 100;
	}
	if (bs_color)
	{
	    brightadj = PCT_MEDIUM_BOTTOM_BASE +
		(brightness * PCT_MEDIUM_BOTTOM_RANGE + 50) / 100;
	    bs_color->red = (_widgetBackground.red * brightadj + 50) / 100;
	    bs_color->green = (_widgetBackground.green * brightadj + 50) / 100;
	    bs_color->blue = (_widgetBackground.blue * brightadj + 50) / 100;
	}
    }
}

void
_XmForegroundColorDefault(Widget w,
			  int offset,
			  XrmValue *val)
{
    static Pixel foreground;

    val->addr = (XPointer)&foreground;
    val->size = sizeof foreground;
    foreground = _XmAccessColorData(_XmGetColors(XtScreenOfObject(w),
						 ColormapOfObject(w),
						 XmIsGadget(w) ?
						 XmParentBackground(w) :
						 XtBackground(w)),
				    XmFOREGROUND);
}

void
_XmHighlightColorDefault(Widget w,
			 int offset,
			 XrmValue *val)
{
    static Pixel highlight;

    val->addr = (XPointer)&highlight;
    val->size = sizeof highlight;
    highlight = _XmAccessColorData(_XmGetColors(XtScreenOfObject(w),
						ColormapOfObject(w),
						XmIsGadget(w) ?
						XmParentBackground(w) :
						XtBackground(w)),
				   XmFOREGROUND);
}

void
_XmBackgroundColorDefault(Widget w,
			  int offset,
			  XrmValue *val)
{
    XColor *xc;
    XmColorData *cc;
    XmColorData cd;
    static Pixel background;

    cd.screen = XtScreenOfObject(w);
    if (DefaultDepthOfScreen(cd.screen) == 1)
    {
	/* The default background color of B/W screen in always white. */

	val->size = sizeof background;
	val->addr = (XPointer)&background;
	background = WhitePixelOfScreen(cd.screen);
	return;
    }
    cd.color_map = ColormapOfObject(w);

    /* Look for an XColor associated with the screen */

    if (!background_color_context)
	background_color_context = XUniqueContext();
    if (XFindContext(DisplayOfScreen(cd.screen),
		     RootWindowOfScreen(cd.screen),
		     background_color_context,
		     (XPointer *)&xc) == XCSUCCESS)
    {
	/* Found it.  Make sure it's in the cache (a la _XmGetColors) */

	cd.allocated = 0;
	cd.background = *xc;
	cd.foreground.pixel =
	    cd.top_shadow.pixel =
	    cd.bottom_shadow.pixel =
	    cd.select.pixel = 0;
	cc = _XmAddToColorCache( &cd);
	if (!(cc->allocated & XmBACKGROUND))
	{
	    cc->allocated |= XmBACKGROUND;
	    call_color_proc(cc);
	}
	val->size = sizeof background;
	val->addr = (XPointer)&background;
	background = cd.background.pixel;
    }
    else
    {
	/* Put the color in the cache */

	_XmAddBackgroundToColorCache(cd.screen,
				   cd.color_map,
				   _XmGetDefaultBackgroundColorSpec(cd.screen),
#if XmVERSION == 1
				   0x729fff,
#else
				   0xc4c4c4,
#endif
				   val);

	/* Save the XColor (which is now in the front of the color cache). */

	xc = XtNew(XColor);
	*xc = color_cache->background;
	XSaveContext(DisplayOfScreen(cd.screen),
		     RootWindowOfScreen(cd.screen),
		     background_color_context,
		     (XPointer)xc);
    }
}


void
_XmTopShadowColorDefault(Widget w,
			 int offset,
			 XrmValue *val)
{
    static Pixel top_shadow;

    val->addr = (XPointer)&top_shadow;
    val->size = sizeof top_shadow;
    top_shadow = _XmAccessColorData(_XmGetColors(XtScreenOfObject(w),
						 ColormapOfObject(w),
						 XmIsGadget(w) ?
						 XmParentBackground(w) :
						 XtBackground(w)),
				    XmTOP_SHADOW);
}


void
_XmBottomShadowColorDefault(Widget w,
			    int offset,
			    XrmValue *val)
{
    static Pixel bottom_shadow;

    val->addr = (XPointer)&bottom_shadow;
    val->size = sizeof bottom_shadow;
    bottom_shadow = _XmAccessColorData(_XmGetColors(XtScreenOfObject(w),
						    ColormapOfObject(w),
						    XmIsGadget(w) ?
						    XmParentBackground(w) :
						    XtBackground(w)),
				       XmBOTTOM_SHADOW);
}

void
_XmSelectColorDefault(Widget w,
		      int offset,
		      XrmValue *val)
{
    static Pixel select;

    val->addr = (XPointer)&select;
    val->size = sizeof select;
    select = _XmAccessColorData(_XmGetColors(XtScreenOfObject(w),
					     ColormapOfObject(w),
					     XmIsGadget(w) ?
					     XmParentBackground(w) :
					     XtBackground(w)),
				XmSELECT);
}

/* Get the name of the default background color for a widget on this screen */

String
_XmGetDefaultBackgroundColorSpec(Screen *screen)
{
    String background_spec;
    XrmValue val;
    String str_type;

    /* It would have made so much sense to make this a Screen resource.
     * Instead, associate a background color with a screen in the same way
     * the screen object is associated.
     */

    if (!background_spec_context)
	background_spec_context = XUniqueContext();
    else if (XFindContext(DisplayOfScreen(screen),
			  RootWindowOfScreen(screen),
			  background_spec_context,
			  &background_spec) == XCSUCCESS)
	return background_spec;

    /* The "default default" is a top-level "background" resource.
     * But we want the name, not the pixel value, so look in the
     * resource database directly.  Failing that, the "default default default"
     * is that classic blue.
     */

    background_spec = XrmGetResource(XtScreenDatabase(screen), XmNbackground,
	XmNbackground, &str_type, &val) && !strcmp( str_type, XmRString)
	? val.addr
#if XmVERSION == 1
	: "rgb:72/9f/ff";
#else
	: "rgb:c4/c4/c4";
#endif

    XSaveContext(DisplayOfScreen(screen),
		 RootWindowOfScreen(screen),
		 background_spec_context,
		 XtNewString(background_spec));
    return background_spec;
}

/* Set a new default background color for this screen */

void
_XmSetDefaultBackgroundColorSpec(Screen *screen, String new_color_spec)
{
    String background;

    /* Set the color string to get later */

    if (!background_spec_context)
	background_spec_context = XUniqueContext();
    else if (XFindContext(DisplayOfScreen(screen),
		     RootWindowOfScreen(screen),
		     background_spec_context,
		     &background) == XCSUCCESS)
    {
	XtFree(background);
	XDeleteContext(DisplayOfScreen(screen),
		       RootWindowOfScreen(screen),
		       background_spec_context);
    }
    XSaveContext(DisplayOfScreen(screen),
		 RootWindowOfScreen(screen),
		 background_spec_context,
		 XtNewString(new_color_spec));

    /* Clear any saved XColor */

    if (background_color_context)
	XDeleteContext(DisplayOfScreen(screen),
		       RootWindowOfScreen(screen),
		       background_color_context);
}

/* According to code given to me by segg@reseau.com, this does work I
 * already do in XmColorProcDefaultProc: it makes the threshold resources
 * for the Screen object available for color proc use.  I don't see a reason
 * I shouldn't continue making them available where I do, so I'm putting
 * an empty function here to signify it does nothing not already done.   - JHG
 */

void
_XmGetDefaultThresholdsForScreen(Screen *screen)
{
}

/*
 * conversion args for the pixmap converters.  Thanks to Gilles Seguin
 * for pointing out the lack.
 */
#define POFFSET(field) \
    (XtPointer)XtOffsetOf(XmPrimitiveRec, field)
#define MOFFSET(field) \
    (XtPointer)XtOffsetOf(XmManagerRec, field)

/* background for everyone */
static XtConvertArgRec backgroundArgs[] =
{
    {
	XtBaseOffset, (XtPointer)XtOffsetOf(CoreRec, core.self),
	sizeof(WidgetRec *)
    }
};


/* primitive foreground */
static XtConvertArgRec PrimForegroundPixmapArgs[] =
{
    {
	XtBaseOffset, POFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtBaseOffset, POFFSET(primitive.foreground), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.depth), sizeof(Cardinal)
    }
};

/* primitive highlight */
static XtConvertArgRec PrimHighlightPixmapArgs[] =
{
    {
	XtBaseOffset, POFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtBaseOffset, POFFSET(primitive.highlight_color), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.depth), sizeof(Cardinal)
    }
};

/* primitive topShadow */
static XtConvertArgRec PrimTopShadowPixmapArgs[] =
{
    {
	XtBaseOffset, POFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtBaseOffset, POFFSET(primitive.highlight_color), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.depth), sizeof(Cardinal)
    }
};

/* primitive bottomShadow */
static XtConvertArgRec PrimBottomShadowPixmapArgs[] =
{
    {
	XtBaseOffset, POFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtBaseOffset, POFFSET(primitive.bottom_shadow_color), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, POFFSET(core.depth), sizeof(Cardinal)
    }
};

/* manager foreground */
static XtConvertArgRec ManForegroundPixmapArgs[] =
{
    {
	XtWidgetBaseOffset, MOFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtWidgetBaseOffset, MOFFSET(manager.foreground), sizeof(Pixel)
    },
    {
	XtWidgetBaseOffset, MOFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtWidgetBaseOffset, MOFFSET(core.depth), sizeof(Cardinal)
    }
};

/* manager highlight */
static XtConvertArgRec ManHighlightPixmapArgs[] =
{
    {
	XtWidgetBaseOffset, MOFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtWidgetBaseOffset, MOFFSET(manager.highlight_color), sizeof(Pixel)
    },
    {
	XtWidgetBaseOffset, MOFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, MOFFSET(core.depth), sizeof(Cardinal)
    }
};

/* manager topShadow */
static XtConvertArgRec ManTopShadowPixmapArgs[] =
{
    {
	XtWidgetBaseOffset, MOFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtWidgetBaseOffset, MOFFSET(manager.top_shadow_color), sizeof(Pixel)
    },
    {
	XtWidgetBaseOffset, MOFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, MOFFSET(core.depth), sizeof(Cardinal)
    }
};

/* manager bottomShadow */
static XtConvertArgRec ManBottomShadowPixmapArgs[] =
{
    {
	XtWidgetBaseOffset, MOFFSET(core.screen), sizeof(Screen *)
    },
    {
	XtWidgetBaseOffset, MOFFSET(manager.bottom_shadow_color), sizeof(Pixel)
    },
    {
	XtWidgetBaseOffset, MOFFSET(core.background_pixel), sizeof(Pixel)
    },
    {
	XtBaseOffset, MOFFSET(core.depth), sizeof(Cardinal)
    }
};

/* gadget pixmap */
static XtConvertArgRec gadgetPixmapArgs[] =
{
    {
	XtBaseOffset, (XtPointer)XtOffsetOf(XmGadgetRec, object.parent),
	sizeof(WidgetRec *)
    }
};

static char *background_pixmap_name = NULL;

char *
_XmGetBGPixmapName(void)
{
    return background_pixmap_name;
}

void
_XmClearBGPixmap(void)
{
    background_pixmap_name = NULL;
}

static Boolean
CvtStringToBackgroundPixmap(Display *display,
			    XrmValuePtr args, Cardinal *num_args,
			    XrmValuePtr fromVal, XrmValuePtr toVal,
			    XtPointer *converter_data)
{
    static Pixmap buf;

    DEBUGOUT(XdbDebug(__FILE__, NULL,
		      "CvtStringToBackgroundPixmap: %s\n",
		      fromVal->addr));

    if (!XtIsShell((Widget)args[0].addr))
    {
	background_pixmap_name = (String)fromVal->addr;
    }

    if (toVal->addr != NULL)
    {
	if( toVal->size < sizeof(Pixmap))
	{
	    toVal->size = sizeof(Pixmap);

	    return False;
	}
	else
	{
	    *((Pixmap *)(toVal->addr)) = XmUNSPECIFIED_PIXMAP;
	    toVal->size = sizeof(Pixmap);

	    return True;
	}
    }
    else
    {
	buf = XmUNSPECIFIED_PIXMAP;
	toVal->addr = (XtPointer)&buf;
	toVal->size = sizeof(Pixmap);

	return True;
    }
}

static void
BuildPixmap(int ncargs, char *which,
	    XrmValuePtr args, Cardinal *num_args,
	    XrmValuePtr fromVal, XrmValuePtr toVal)
{
    static Pixmap pixmap;
    Screen *screen;
    Pixel foreground;
    Pixel background;
    Cardinal depth;
    char *name = fromVal->addr;

    pixmap = XmUNSPECIFIED_PIXMAP;

    toVal->addr = (char *)&pixmap;
    toVal->size = sizeof(Pixmap);

    if (*num_args != ncargs)
    {
	XtWarningMsg("wrongParameters", which, "XmToolkitError",
		     "String to Pixmap conversion needs four argument",
		     (String *)NULL, (Cardinal *)NULL);

	return;
    }

    if (strcmp(name, "unspecified_pixmap") == 0)
    {
	return;
    }

    screen = *((Screen **)args[0].addr);
    foreground = *((Pixel *)args[1].addr);
    background = *((Pixel *)args[2].addr);
    depth = *((Cardinal *)args[3].addr);

    pixmap = XmGetPixmapByDepth(screen, name,
				foreground, background, depth);
}

static void
_XmCvtStringToPrimForegroundPixmap(XrmValuePtr args, Cardinal *num_args,
				   XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToPrimForegroundPixmap\n"));

    BuildPixmap(XtNumber(PrimForegroundPixmapArgs),
		"_XmCvtStringToPrimForegroundPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToPrimHighlightPixmap(XrmValuePtr args, Cardinal *num_args,
				  XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToPrimHighlightPixmap\n"));

    BuildPixmap(XtNumber(PrimHighlightPixmapArgs),
		"_XmCvtStringToPrimHighlightPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToPrimTopShadowPixmap(XrmValuePtr args, Cardinal *num_args,
				  XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToPrimTopShadowPixmap\n"));

    BuildPixmap(XtNumber(PrimTopShadowPixmapArgs),
		"_XmCvtStringToPrimTopShadowPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToPrimBottomShadowPixmap(XrmValuePtr args, Cardinal *num_args,
				     XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToPrimBottomShadowPixmap\n"));

    BuildPixmap(XtNumber(PrimBottomShadowPixmapArgs),
		"_XmCvtStringToPrimBottomShadowPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToManForegroundPixmap(XrmValuePtr args, Cardinal *num_args,
				  XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToManForegroundPixmap\n"));

    BuildPixmap(XtNumber(ManForegroundPixmapArgs),
		"_XmCvtStringToManForegroundPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToManHighlightPixmap(XrmValuePtr args, Cardinal *num_args,
				 XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToManHighlightPixmap\n"));

    BuildPixmap(XtNumber(ManHighlightPixmapArgs),
		"_XmCvtStringToManHighlightPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToManTopShadowPixmap(XrmValuePtr args, Cardinal *num_args,
				 XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToManTopShadowPixmap\n"));

    BuildPixmap(XtNumber(ManTopShadowPixmapArgs),
		"_XmCvtStringToManTopShadowPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToManBottomShadowPixmap(XrmValuePtr args, Cardinal *num_args,
				    XrmValuePtr fromVal, XrmValuePtr toVal)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToManBottomShadowPixmap\n"));

    BuildPixmap(XtNumber(ManBottomShadowPixmapArgs),
		"_XmCvtStringToManBottomShadowPixmap",
		args, num_args, fromVal, toVal);
}

static void
_XmCvtStringToGadgetPixmap(XrmValuePtr args, Cardinal *num_args,
			   XrmValuePtr fromVal, XrmValuePtr toVal)
{
    XrmValue pargs[4];
    Cardinal pnargs = 4;
    Widget parent;

    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmCvtStringToGadgetPixmap\n"));

    parent = *((Widget *)args[0].addr);

    pargs[0].addr = (XPointer)&CoreScreen(parent);
    pargs[1].addr = (XPointer)&MGR_Foreground(parent);
    pargs[2].addr = (XPointer)&CoreBackground(parent);
    pargs[3].addr = (XPointer)&CoreDepth(parent);

    BuildPixmap(pnargs, "_XmCvtStringToGadgetPixmap",
		pargs, &pnargs, fromVal, toVal);
}

void
_XmRegisterPixmapConverters(void)
{
    static Boolean inited = False;
  
    DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmRegisterPixmapConverters(%d)\n",
	__FILE__, __LINE__));

    if (inited)
    {
	return;
    }

    inited = True;

    XtSetTypeConverter(XtRString, XmRXmBackgroundPixmap,
                       CvtStringToBackgroundPixmap, backgroundArgs,
		       XtNumber(backgroundArgs), XtCacheNone, NULL);
    XtSetTypeConverter(XtRString, XmRPixmap,
                       CvtStringToBackgroundPixmap, backgroundArgs,
		       XtNumber(backgroundArgs), XtCacheNone, NULL);

    XtAddConverter(XtRString, XmRPrimForegroundPixmap,
                   _XmCvtStringToPrimForegroundPixmap, PrimForegroundPixmapArgs,
		   XtNumber(PrimForegroundPixmapArgs));
    XtAddConverter(XtRString,  XmRHighlightPixmap,
                   _XmCvtStringToPrimHighlightPixmap, PrimHighlightPixmapArgs,
		   XtNumber(PrimHighlightPixmapArgs));
    XtAddConverter(XtRString, XmRTopShadowPixmap,
                   _XmCvtStringToPrimTopShadowPixmap, PrimTopShadowPixmapArgs,
		   XtNumber(PrimTopShadowPixmapArgs));
    XtAddConverter(XtRString,  XmRBottomShadowPixmap,
                   _XmCvtStringToPrimBottomShadowPixmap,
		   PrimBottomShadowPixmapArgs,
		   XtNumber(PrimBottomShadowPixmapArgs));

    XtAddConverter(XtRString,  XmRManForegroundPixmap,
                   _XmCvtStringToManForegroundPixmap, ManForegroundPixmapArgs,
		   XtNumber(ManForegroundPixmapArgs));
    XtAddConverter(XtRString,  XmRManHighlightPixmap,
                   _XmCvtStringToManHighlightPixmap, ManHighlightPixmapArgs,
		   XtNumber(ManHighlightPixmapArgs));
    XtAddConverter(XtRString,  XmRManTopShadowPixmap,
                   _XmCvtStringToManTopShadowPixmap, ManTopShadowPixmapArgs,
		   XtNumber(ManTopShadowPixmapArgs));
    XtAddConverter(XtRString,  XmRManBottomShadowPixmap,
                   _XmCvtStringToManBottomShadowPixmap,
		   ManBottomShadowPixmapArgs,
		   XtNumber(ManBottomShadowPixmapArgs));

    XtAddConverter(XtRString,  XmRGadgetPixmap,
                   _XmCvtStringToGadgetPixmap, gadgetPixmapArgs,
		   XtNumber(gadgetPixmapArgs));

#if 0
    XtSetTypeConverter(XtRString,  XmRAnimationMask,
		       CvtStringToAnimationMask,
                       backgroundArgs, XtNumber(backgroundArgs),
		       XtCacheNone, NULL);

    XtSetTypeConverter(XtRString, XmRAnimationPixmap,
		       CvtStringToAnimationPixmap,
                       backgroundArgs, XtNumber(backgroundArgs),
		       XtCacheNone, NULL);
#endif
}

/*
 * These functions (_XmBlackPixel and _XmWhitePixel) appear in
 * libXm:Obso2_0.o in the Motif 2 libraries.  The prototypes are in
 * Xm/XmP.h but there were no implementations.
 *
 * The final XColor parameter makes no sense to me at all but the Motif
 * headers on HP-UX 9.05 specify a raw XColor (as opposed to the more
 * sensible XColor*) too so the signatures are correct.
 *
 * I don't know the proper behavior of these functions so I'm guessing.
 *
 *	--mu@echo-on.net, 1998.03.15
 */
Pixel
_XmWhitePixel(Screen *screen, Colormap colormap, XColor whitecolor)
{
    static Screen *last_screen;
    static Colormap last_colormap;
    static Pixel last_pixel;

    if (colormap == DefaultColormapOfScreen(screen))
	return WhitePixelOfScreen(screen);
    if (screen == last_screen && colormap == last_colormap)
	return last_pixel;

    last_screen = screen;
    last_colormap = colormap;
    whitecolor.red   =
    whitecolor.green =
    whitecolor.blue  = USHRT_MAX;
    if (XAllocColor(DisplayOfScreen(screen), colormap, &whitecolor))
    {
	last_pixel = whitecolor.pixel;
    }
    else
    {
	DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmWhitePixel(%d) - Could not allocate white color\n",
			   __FILE__,__LINE__));
	color_fail_warn();
	last_pixel = WhitePixelOfScreen(screen);
    }
    return last_pixel;
}

Pixel
_XmBlackPixel(Screen *screen, Colormap colormap, XColor blackcolor)
{
    static Screen *last_screen;
    static Colormap last_colormap;
    static Pixel last_pixel;

    if (colormap == DefaultColormapOfScreen(screen))
	return BlackPixelOfScreen(screen);
    if (screen == last_screen && colormap == last_colormap)
	return last_pixel;

    last_screen = screen;
    last_colormap = colormap;
    blackcolor.red   =
    blackcolor.green =
    blackcolor.blue  = 0;
    if (XAllocColor(DisplayOfScreen(screen), colormap, &blackcolor))
    {
	last_pixel = blackcolor.pixel;
    }
    else
    {
	DEBUGOUT(XdbDebug0(__FILE__, NULL, "%s:_XmBlackPixel(%d) - Could not allocate black color\n",
			   __FILE__,__LINE__));
	color_fail_warn();
	last_pixel = BlackPixelOfScreen(screen);
    }
    return last_pixel;
}

/*
 * More convenient forms of _XmWhitePixel and _XmBlackPixel.
 * These can't be macros because the stupid last parameter is a raw structure
 * rather than a pointer.
 */
Pixel
_XmWhitePixelOfObject(Widget w)
{
    XColor unused;
    return _XmWhitePixel(XtScreenOfObject(w), ColormapOfObject(w), unused);
}

Pixel
_XmBlackPixelOfObject(Widget w)
{
    XColor unused;
    return _XmBlackPixel(XtScreenOfObject(w), ColormapOfObject(w), unused);
}
