ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/objcX-0.87.tgz#/objcX-0.87/dpsclient/xttools.c

This is xttools.c in view mode; [Download] [Up]

/* xttools - Color conversion routines and other low-level X support

   Copyright (C) 1995 Free Software Foundation, Inc.

   Written by:  Adam Fedor <fedor@boulder.colorado.edu>
   Date: Nov 1994
   
   This file is part of the GNU Objective C User Interface 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.
   */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xatom.h>
#include "xttools.h"
#include "appkit/stdmacros.h"

#define XW_STD_COLORMAP_STR	"XWStdColormap"
#define XW_GRAY_COLORMAP_STR	"XWGrayColormap"
#define XW_RGB_COLORMAP_STR	"XWRGBColormap"
/*
static Atom	XW_GRAY_COLORMAP = 0;
static Atom	XW_RGB_COLORMAP = 0;
*/
/* Right now we define the colormaps to be X default colormaps, since 
   maybe the window manager might actually have one of these */
static Atom	XW_GRAY_COLORMAP = XA_RGB_GRAY_MAP;
static Atom	XW_RGB_COLORMAP = XA_RGB_BEST_MAP;
static Atom	XW_STD_COLORMAP = 0;

static void 
xtInitAtoms(XWContext context)
{
    if (XW_GRAY_COLORMAP == 0) {
    	XW_GRAY_COLORMAP = XInternAtom(context->display, 
		XW_GRAY_COLORMAP_STR, 0);
    	XW_RGB_COLORMAP = XInternAtom(context->display, 
		XW_RGB_COLORMAP_STR, 0);
    }
}

/* Maintaining and using colormaps */
int
xtSetGrayColormap(XWContext context, XStandardColormap *stdmap, 
	unsigned long *cells, unsigned int colors)
{
    int i;
    XColor color;

    for (i=0; i < colors; i++) {
	/* Careful to scale color from 0 to 65536 */
	color.red = color.green = color.blue = i * 256 * (256.0 / colors);
	color.flags = DoRed | DoGreen | DoBlue;
	if (cells)
	    color.pixel = cells[i];
	else
	    color.pixel = i;
	XStoreColor(context->display, stdmap->colormap, &color);
    }
    stdmap->red_max = colors - 1;
    stdmap->red_mult = 1;
    stdmap->green_max = 0;
    stdmap->green_mult = 0;
    stdmap->blue_max = 0;
    stdmap->blue_mult = 0;
    stdmap->base_pixel = 0;
    if (cells) 
	stdmap->base_pixel = cells[0];
    return 0;
}

/* Not implemented. FIXME */
int
xtSetRGBColormap(XWContext context, XStandardColormap *stdmap, 
	unsigned long *cells, unsigned int colors)
{
    return 0;
}

/* Given a mask, find the minimum value where (number & mask) != 0 */
unsigned long
mask_min(unsigned long mask)
{
    unsigned long number = 1;
    if (mask == 0)
	return 0;
    while ((number & mask) == 0)
      number = (number << 1L);
    return number;
}

/* Gets and or creates a standard colormap for the visual type of the
   display. On some displays, there is no need for a color map, so we
   just store the characteristics of the display. On PseudoColor
   displays we try to allocate as many colors as possible in a shared
   colormap. If no colors are availible, use the default Black/White
   pixel.

   Use (or will use) the following hints:
     NSStdColormap - (best or gray) will look for the specified standard
       colomap and use it instead of creating a colormap.

     NSMaxColors - Will allocate less than the specified number of colors.

     NSPrivateColormap - Will allocate a private map if needed.

*/
XStandardColormap *
xtDefaultColormap(XWContext context)
{
    int i, map_count;
    unsigned int 	colors;
    unsigned long 	*cells;
    XStandardColormap 	*stdmap;
    int NSMaxColors, NSPrivateColormap;

    if (context->map)
	return context->map;

    /* Did  the window manager already create a colormap for us? */
    xtInitAtoms(context);
    if (XW_STD_COLORMAP == 0) {
	const char *NSStdColormap = getenv("COLORMAP");
	if (NSStdColormap && NSStdColormap[0] == 'b')
	    XW_STD_COLORMAP = XW_RGB_COLORMAP;
	else if (NSStdColormap && NSStdColormap[0] == 'g')
	    XW_STD_COLORMAP = XW_GRAY_COLORMAP;
    	else if (context->vinfo.class == DirectColor 
		|| context->vinfo.class == TrueColor)
	    XW_STD_COLORMAP = XW_RGB_COLORMAP;
    	else
	    XW_STD_COLORMAP = XW_GRAY_COLORMAP;
    }
    i = XGetRGBColormaps(context->display,
		DefaultRootWindow(context->display),
		&stdmap,
		&map_count,
		XW_STD_COLORMAP);
    if (i) {
	context->map = stdmap;
	return stdmap;
    }

    /* Didn't find the standard map, create our own */
    NX_MALLOC(stdmap, XStandardColormap, 1);

    /* Note: in many cases we just set stdmap->colormap to 0, since this is
       only needed to tell the Window which colormap to install, if colormap
       == 0, then we're using the DefaultColormap, and there is no need to
       install it.
    */
    if (context->vinfo.class == DirectColor
		|| context->vinfo.class == TrueColor) {
	stdmap->colormap = 0;
    	stdmap->red_mult = mask_min(context->vinfo.red_mask);
    	stdmap->red_max = context->vinfo.red_mask / stdmap->red_mult;
    	stdmap->green_mult = mask_min(context->vinfo.green_mask);
    	stdmap->green_max = context->vinfo.green_mask / stdmap->green_mult;
    	stdmap->blue_mult = mask_min(context->vinfo.blue_mask);
    	stdmap->blue_max = context->vinfo.blue_mask / stdmap->blue_mult;
    	stdmap->base_pixel = 0;
	context->map = stdmap;
	return stdmap;
    } else if (context->vinfo.class == StaticGray) {
	stdmap->colormap = 0;
    	stdmap->red_max = context->vinfo.colormap_size - 1;
    	stdmap->red_mult = 1;
    	stdmap->green_max = 0;
    	stdmap->green_mult = 0;
    	stdmap->blue_max = 0;
    	stdmap->blue_mult = 0;
    	stdmap->base_pixel = 0;
	context->map = stdmap;
	return stdmap;
    }

    /* How do you figure out the colormap structure for StaticColor? Punt */
    /* FIXME */
    if (context->vinfo.class == StaticColor) {
	fprintf(stderr, "Error (xttools): Can't determine colormap for StaticColor displays\n");
	return NULL;
    }

    /* Only thing left is PseudoColor and GrayScale, which can be handled the
       same */
    if (context->vinfo.class != PseudoColor 
		&& context->vinfo.class != GrayScale) {
	fprintf(stderr, "Error (xttools): Unknown visual class \n");
	return NULL;
    }

    /* FIXME: Get these defaults */
    NSMaxColors = context->vinfo.colormap_size - 8;
    NSPrivateColormap = 0;

    colors = NSMaxColors;
    stdmap->colormap = DefaultColormap(context->display, 
		DefaultScreen(context->display));
    i = 0;
    while (i == 0 && colors >= 4) {
    	NX_MALLOC(cells, unsigned long, colors);
    	i = XAllocColorCells(context->display, 
		stdmap->colormap,
		TRUE,
		NULL,
		0,
		cells,
		colors);
	if (i == 0) {
	    NX_FREE(cells);
	    cells = NULL;
    	    colors = colors - 4;
	}
    }

    if (i == 0) 
      {
    	NX_FREE(cells);
	cells = NULL;
	if (NSPrivateColormap)
	  {
	    fprintf(stderr, "Warning (xttools): No colors available, creating private map\n");
	    colors = NSMaxColors;
	    stdmap->colormap = XCreateColormap(context->display, 
		DefaultRootWindow(context->display),
		context->vinfo.visual,
		AllocAll);
	  }
	else
	  {
	    fprintf(stderr, "Warning (xttools): No colors available,
using standard BlackPixel/WhitePixel\n");
	    context->map = NULL;
	    return NULL;
	  }
      } 
    else if (colors < 64)
      fprintf(stderr, 
	      "Warning: (xttools): Degraded colormap, only %d colors\n",
	      colors);

    /* Now set up the cells */
    if (XW_STD_COLORMAP == XW_RGB_COLORMAP)
    	xtSetRGBColormap(context, stdmap, cells, colors);
    else
    	xtSetGrayColormap(context, stdmap, cells, colors);

    /*  Need to change the GC so that Background and Foreground
	pixels are properly set. This is down in xmView when creating
	the gstate.
    */
    context->map = stdmap;
    return stdmap;
}

/* Internal conversion of colors to pixels values */
u_long   
xtGrayToPixel(XWContext context, float gray)
{
    XStandardColormap *map;
    u_long color;

    map = context->map;
    if (map == NULL) {
	int screen = DefaultScreen(context->display);
	return (gray < 0.5) ? BlackPixel(context->display, screen)
		: WhitePixel(context->display, screen);
    }
    color = ((u_long)(0.5 + (gray * map->red_max)) * map->red_mult)
		+ ((u_long)(0.5 + (gray*map->green_max)) * map->green_mult)
		+ ((u_long)(0.5 + (gray*map->blue_max)) * map->blue_mult)
		+ map->base_pixel;
    return color;
}

u_long   
xtRGBToPixel(XWContext context, float red, float green, float blue)
{
    XStandardColormap *map;
    u_long color;

    map = context->map;
    if (map == NULL) {
	int gray = ((0.3*red) + (0.59*green) + (0.11*blue));
	int screen = DefaultScreen(context->display);
	return (gray < 0.5) ? BlackPixel(context->display, screen)
		: WhitePixel(context->display, screen);
    }
    color = ((u_long)(0.5 + (red * map->red_max)) * map->red_mult)
		+ ((u_long)(0.5 + (green * map->green_max)) * map->green_mult)
		+ ((u_long)(0.5 + (blue * map->blue_max)) * map->blue_mult)
		+ map->base_pixel;
    return color;
}

/* Not implemented. FIXME */
u_long   
xtHSBToPixel(XWContext context, float h, float s, float b)
{
    return 0;
}

/* Not implemented. FIXME */
u_long   
xtCMYKToPixel(XWContext context, float c, float m, float y, float k) 
{
    return 0;
}

u_long   
xtColorToPixel(XWContext context, device_color_t  color)
{
  u_long pix;
  switch(color.space)
    {
    case gray_colorspace:
      pix = xtGrayToPixel(context, color.field[0]);
      break;
    case rgb_colorspace:
      pix = xtRGBToPixel(context, color.field[0], 
			 color.field[1], color.field[2]);
      break;
    case hsb_colorspace:
      pix = xtHSBToPixel(context, color.field[0], 
			 color.field[1], color.field[2]);
      break;
    case cmyk_colorspace: 
      pix = xtCMYKToPixel(context, color.field[0], color.field[1],
			  color.field[2], color.field[3]);
      break;
    default:
      break;
    }
    return pix;
}

device_color_t 
xtConvertToGray(device_color_t color)
{
  device_color_t new;

  new.space = gray_colorspace;
  switch(color.space)
    {
    case gray_colorspace:
      new = color;
      break;
    case hsb_colorspace:
    case cmyk_colorspace: 
      color = xtConvertToRGB(color);
      /* NO BREAK */
    case rgb_colorspace:
      new.field[0] = 
	((0.3*color.field[0]) + (0.59*color.field[1]) + (0.11*color.field[2]));
      break;
    default:
      break;
    }
  return new;
}

device_color_t 
xtConvertToRGB(device_color_t color)
{
  device_color_t new;

  new.space = rgb_colorspace;
  switch(color.space)
    {
    case gray_colorspace:
      new.field[0] = color.field[0];
      new.field[1] = color.field[0];
      new.field[2] = color.field[0];
      break;
    case rgb_colorspace:
      new = color;
      break;
    case hsb_colorspace: 
    case cmyk_colorspace: 
      break;
    default:
      break;
    }
  return new;
}

device_color_t 
xtConvertToHSB(device_color_t color)
{
  device_color_t new;

  new.space = hsb_colorspace;
  switch(color.space)
    {
    case gray_colorspace:
      break;
    case rgb_colorspace:
      break;
    case hsb_colorspace: 
      new = color;
      break;
    case cmyk_colorspace: 
      break;
    default:
      break;
    }
  return new;
}

device_color_t 
xtConvertToCMYK(device_color_t color)
{
  device_color_t new;

  new.space = gray_colorspace;
  switch(color.space)
    {
    case gray_colorspace:
      break;
    case rgb_colorspace:
      break;
    case hsb_colorspace:
      break;
    case cmyk_colorspace: 
      new = color;
      break;
    default:
      break;
    }
  return new;
}

/* Internal conversion of image data to pixel values
   These routines are here for consistency, but are really only used by
   xtNXBitmapImageRep.  Look at that file for more information on how these
   routines are used.
*/
u_char   *
xtMapGrays(XWContext context, u_char **src, int colorspace, int bps, int spp, 
	int ncolors, int planar, u_char *dest)
{
    int i;
    XStandardColormap *map;
    u_int  max;
    u_long color;
    u_char *gray;

    map = context->map;
    gray = src[0];	/* Ignore alpha */
    if (map == NULL)
	return 0;
    max = (1 << bps);
    for (i=0; i < ncolors; i++) {
	/* Just skip the Alpha if there is one */
    	if (planar)
	    color = (gray[i*bps/8] << ((i * bps) % 8)) % max;
	else
	    color = (gray[i*spp*bps/8] << ((i * bps) % 8)) % max;
	color = ((color * map->red_max / max) * map->red_mult
		+ (color * map->green_max / max) * map->green_mult
		+ (color * map->blue_max / max) * map->blue_mult
		+ map->base_pixel) & 0xFFFFFFFF;
	/* FIXME: Need to pack bits for displays with depth < 8 */
	dest[i] = color;
    }

    return dest;
}

/* FIXME: Only handles RGB images (no CMYK) */
u_char   *
xtMapColors(XWContext context, u_char **src, int colorspace, int bps, int spp, 
		int ncolors, int planar, u_char *dest)

{
    int i;
    XStandardColormap *map;
    u_int  max;
    u_long color;
    u_char *red, *green, *blue;
    u_char r, g, b;

    if (spp <= 2)
	return xtMapGrays(context, src, colorspace, bps, 
		spp, ncolors, planar, dest);

    map = context->map;
    if (map == NULL)
	return 0;
    max = (1 << bps);
    red = src[0];
    if (planar) {
	green = src[1];
	blue = src[2];
    }
    for (i=0; i < ncolors; i++) {
	u_int shift;
	shift = i * bps / 8;
	if (planar) {
	    r = (red[shift]   << ((i * bps) % 8)) % max;
	    g = (green[shift] << ((i * bps) % 8)) % max;
	    b = (blue[shift]  << ((i * bps) % 8)) % max;
	    /* Translate values for gray-scale display */
	    if ( map->green_max == 0 && map->blue_max == 0)
		r = (u_long)((0.3*r) + (0.59*g) + (0.11*b));
	    color = ((r * map->red_max / max) * map->red_mult
		+ (g * map->green_max / max)*map->green_mult
		+ (b * map->blue_max / max)*map->blue_mult
		+ map->base_pixel) & 0xFFFFFFFF;
	} else {
	    r = (red[i*spp*bps/8]     << ((i * bps) % 8)) % max;
	    g = (red[(i*spp+1)*bps/8] << (((i+1) * bps) % 8)) % max;
	    b = (red[(i*spp+2)*bps/8] << (((i+2) * bps) % 8)) % max;
	    /* Translate values for gray-scale display */
	    if ( map->green_max == 0 && map->blue_max == 0)
		r = (u_long)((0.3*r) + (0.59*g) + (0.11*b));
	    color = ((r * map->red_max / max) * map->red_mult
		+ (g * map->green_max / max) * map->green_mult
		+ (b * map->blue_max / max) * map->blue_mult
		+ map->base_pixel) & 0xFFFFFFFF;
	}
	/* FIXME: Need to pack bits for displays with depth < 8 */
	dest[i] = color;
    }

    return dest;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.