ftp.nice.ch/pub/next/unix/graphics/urt.3.0.s.tar.gz#/urt.3.0.s/get/getx11/x11_stuff.c

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

/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notices are 
 * preserved on all copies.
 * 
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the 
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */

/* 
 * x11_stuff.c - Do colormaps, visuals, pix_info window...
 * 
 * Author:	Spencer W. Thomas  (x10)
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Thu Feb 20 1986
 * Copyright (c) 1986, University of Utah
 * 
 * Modified:	Andrew F. Vesper (x 11)
 *		High Performance Workstations
 *		Digital Equipment Corp
 * Date:	Fri, Aug 7, 1987
 *		Thu, Jan 14, 1988
 * Copyright (c) 1987,1988, Digital Equipment Corporation
 * 
 * Modified:	Martin R. Friedmann (better X11, flipbook, mag, pix_info)
 * 		Dept of Electrical Engineering and Computer Science
 *		University of Michigan
 * Date:	Tue, Nov 14, 1989
 * Copyright (c) 1989, University of Michigan
 */
#include "getx11.h"

#include "circle.bitmap"
#include "circle_mask.bitmap"

static Boolean init_separate_color_rw(), init_color_rw(),
    init_separate_color_ro(), init_color_ro(), init_mono_rw(), init_mono_ro();
static CONST_DECL char *visual_class_to_string();
extern int get_dither_arrays(), shift_match_left(), shift_match_right();

Cursor circle_cursor = NULL;
Cursor left_ptr_cursor = NULL;
Cursor watch_cursor = NULL;


static image_information *wait_img = NULL;

void set_watch_cursor( window )
Window window;    
{
    XDefineCursor( dpy, window, watch_cursor );
    XFlush(dpy);
}

void set_circle_cursor( window )
Window window;    
{
    XDefineCursor( dpy, window, circle_cursor );
    XFlush(dpy);
}

void set_left_ptr_cursor( window )
Window window;    
{
    XDefineCursor( dpy, window, left_ptr_cursor );
    XFlush(dpy);
}

void get_cursors( window )
Window window;
{
    if (circle_cursor == NULL)
	circle_cursor = XCreateFontCursor (dpy, XC_circle);
    
    if (watch_cursor == NULL)
	watch_cursor = XCreateFontCursor (dpy, XC_watch);

    if (left_ptr_cursor == NULL)
	left_ptr_cursor = XCreateFontCursor (dpy, XC_left_ptr);

    if (circle_cursor == NULL) {
	Pixmap	source;
	Pixmap	mask;
	XColor	color_1;
	XColor	color_2;
	
	source = XCreateBitmapFromData(dpy, window, circle_bits,
				       circle_width, circle_height);
	
	mask = XCreateBitmapFromData(dpy, window, circle_mask_bits,
				     circle_width, circle_height);
	
	color_1.pixel = WhitePixel (dpy, screen);
	color_1.red   = 0xffff;
	color_1.green = 0xffff;
	color_1.blue  = 0xffff;
	color_1.flags = DoRed | DoGreen | DoBlue;
	
	color_1.pixel = BlackPixel (dpy, screen);
	color_2.red   = 0;
	color_2.green = 0;
	color_2.blue  = 0;
	color_2.flags = DoRed | DoGreen | DoBlue;
	
	circle_cursor = XCreatePixmapCursor (dpy, source, mask,
					     &color_1, &color_2,
					     circle_x_hot, circle_y_hot);
	XFreePixmap (dpy, source);
	XFreePixmap (dpy, mask);
    }
    
    if (watch_cursor == NULL)
	watch_cursor = circle_cursor;

    if (left_ptr_cursor == NULL)
	left_ptr_cursor = circle_cursor;
}


XImage *get_X_image( img, width, height )
image_information *img;
int width, height;
{
    XImage 		*image;

    image = XCreateImage (dpy, img->dpy_visual,
				 (img->binary_img ? 1 : img->dpy_depth), 
				 (img->binary_img ? XYBitmap : ZPixmap), 
				 0, NULL, width, height, 32, 0);
    
    if (image != NULL) {
	image->data = (char *)malloc ( image->bytes_per_line * height );
	if ( image->data == NULL) {
	    perror ( "malloc image->data" );
	    XDestroyImage (image);
	    image = NULL;
	}
    }
    return (image);

}

void
determine_icon_size(image_width, image_height,
		    icon_width, icon_height, icon_factor )
int image_width, image_height;
int *icon_width, *icon_height, *icon_factor;
{
    XIconSize	*icon_sizes;
    int	icon_size_count;
    int width, height, factor;
    int i;

    /*
     * We want the Icon to be about DESIRED_ICON_WIDTH x DESIRED_ICON_HEIGHT.  
     * First, make sure that is OK with the window manager.
     * Then figure out the icon scaling factor.
     */
    
#define DESIRED_ICON_WIDTH	48
#define DESIRED_ICON_HEIGHT	48

    width = DESIRED_ICON_WIDTH;
    height = DESIRED_ICON_HEIGHT;
    
    if (XGetIconSizes (dpy, root_window, &icon_sizes, &icon_size_count) 
	&& icon_size_count >= 1) {
	
	for (i = 0; i < icon_size_count; i++) {
	    if (icon_sizes[i].min_width <= DESIRED_ICON_WIDTH
		&& icon_sizes[i].max_width >= DESIRED_ICON_WIDTH
		&& icon_sizes[i].min_height <= DESIRED_ICON_HEIGHT
		&& icon_sizes[i].max_height >= DESIRED_ICON_HEIGHT) {
		break;
	    }
	}

	if (i >= icon_size_count) {
	    width = icon_sizes[0].max_width;
	    height = icon_sizes[0].max_height;
	}
	
    }
    
    factor = image_width / width;
    if (factor < image_height / height) 
	factor = image_height / height;
    if ( factor == 0 )
	factor = 1;
    
    *icon_width = 1 + (image_width / factor);
    *icon_height = 1 + (image_height / factor);
    *icon_factor = factor;
}

static void handle_x_errors( dpy, event)
	Display *dpy;
	XErrorEvent *event;
{
    XID xid = event->resourceid;
    image_information *img = wait_img;
    
    switch ( event->error_code ) {
    case BadAlloc:
	if ( img ) {
	    if ( xid == img->pixmap ){
		img->pixmap = NULL;
		img->pixmap_failed = True;
	    } else
	    if ( xid == img->icn_pixmap ){ 
		img->icn_pixmap = NULL;
		img->pixmap_failed = True;
	    } else
	    if (xid == img->mag_pixmap ){
		img->mag_pixmap = NULL;
		img->pixmap_failed = True;
	    } else
		_XDefaultError (dpy, event);
	    break;
	}
    case BadWindow:
    case BadDrawable:
    case BadMatch:
	_XDefaultError( dpy, event );
	break;
	
    default:
	_XDefaultError( dpy, event );
	break;
    }
}

void get_x_colormap( img )
image_information *img;
{
    img->colormap = XCreateColormap (dpy, root_window,
				     img->dpy_visual, AllocNone );
    if (img->colormap == NULL) 
	fprintf(stderr, "Could not create color map for visual\n");
    
    VPRINTF(stderr, "created colormap for visual type %s\n",
	    visual_class_to_string(img->visual_class));

}    

void check_pixmap_allocation( img )
image_information *img;
{
    wait_img = img;
    XSetErrorHandler( handle_x_errors );
    XSync( dpy, False );
}

/* 
 * Create a window with no help from user.
 */
void
create_windows( img, window_geometry )
char			*window_geometry;
register image_information *img;
{
    static XClassHint	class_hint = {"getx11", "Getx11"};
    char		default_geometry[30];
    int			width, height, x, y;
    XSizeHints		size_hints;
    unsigned int	mask;
    unsigned long	gc_mask;
    XGCValues		gc_values;
    XWMHints		wm_hints;
    XSetWindowAttributes xswa;
    unsigned long	xswa_mask;
    Boolean 		new_window;
    int icn_alloc = False;
    Boolean		new_pixmaps;
    
    /* 
     * Now, make the window.
     */
    
    new_window = (img->window == NULL && img->icn_window == NULL);
    new_pixmaps = ((img->pixmap == NULL || img->icn_pixmap == NULL ||
		    img->mag_pixmap == NULL) &&  !img->pixmap_failed &&
		   !stingy_flag);
    
    if ( !img->window )
    {
	sprintf( default_geometry, "=%dx%d", img->w, img->h );
    
	mask = XGeometry(dpy, screen, window_geometry, default_geometry, 
			 IMAGE_BORDERWIDTH, 1, 1, 0, 0,
			 &x, &y, &width, &height );
	
	size_hints.flags = 0;

	if ( mask & (XValue | YValue) ) {
	    size_hints.flags |= USPosition;
	    size_hints.x = x;
	    size_hints.y = y;
	} else {
	    size_hints.flags |= PPosition;
	    size_hints.x = x = (DisplayWidth(dpy, screen) - width)/2;
	    size_hints.y = y = (DisplayHeight(dpy, screen) - height)/2;
	}
	
	if ( mask & (WidthValue | HeightValue) ) {
	    size_hints.flags |=	USSize;
	    size_hints.width = width;
	    size_hints.height = height;
	}

	wm_hints.flags = InputHint;
	wm_hints.input = True;

	VPRINTF (stderr, "window at (%d, %d) %dx%d\n", 
		 x, y, width, height);
    
	xswa_mask = CWBackPixel | CWEventMask | CWBorderPixel;
	xswa.background_pixel = BlackPixel (dpy, screen);
	xswa.border_pixel = WhitePixel (dpy, screen);
	xswa.event_mask = ButtonPressMask | ExposureMask | KeyPressMask;

	if (img->colormap) {
	    xswa.colormap = img->colormap;
	    xswa_mask |= CWColormap;
	}
	
	img->window = XCreateWindow ( dpy, root_window, x, y, 
				      width, height, 
				      IMAGE_BORDERWIDTH, img->dpy_depth,
				      InputOutput, img->dpy_visual,
				      xswa_mask, &xswa);
    
	    
	XSetNormalHints (dpy, img->window, &size_hints);
	XSetClassHint(dpy, img->window, &class_hint);
	XSetWMHints(dpy, img->window, &wm_hints);
	XSetIconName (dpy, img->window, img->title);
    }
    XStoreName(dpy, img->window, img->title);

    if ( !img->pixmap && new_pixmaps )
	img->pixmap = XCreatePixmap(dpy, img->window, img->w, img->h,
				    img->dpy_depth );

    img->refresh_pixmap = img->pixmap;
    
    if ( !img->icn_window )
    {
	xswa_mask = NULL;
	
	if (img->colormap) {
	    xswa.colormap = img->colormap;
	    xswa_mask = CWColormap;
	}
	
	img->icn_window = XCreateWindow (dpy, root_window, 0, 0,
					 img->icn_w, img->icn_h, 
					 0, img->dpy_depth,
					 InputOutput, img->dpy_visual,
					 xswa_mask, &xswa);
	
	size_hints.flags = PMinSize | PMaxSize;
	size_hints.min_width = img->icn_w;
	size_hints.max_width = img->icn_w;
	size_hints.min_height = img->icn_h;
	size_hints.max_height = img->icn_h;
	
	XSetNormalHints(dpy, img->icn_window, &size_hints);
	XStoreName(dpy, img->icn_window, img->title);
    }

    if ( !img->gc )
    {
	gc_mask = 0;
	gc_values.function = GXcopy;		gc_mask |= GCFunction;
	gc_values.plane_mask = AllPlanes;	gc_mask |= GCPlaneMask;
	gc_values.foreground = white_pixel;	gc_mask |= GCForeground;
	gc_values.background = black_pixel;	gc_mask |= GCBackground;
    
	img->gc = XCreateGC (dpy, img->window, gc_mask, &gc_values);
    }

    if ( !img->icn_pixmap )
    {
	img->icn_pixmap = XCreatePixmap(dpy, img->icn_window, img->icn_w,
					img->icn_h, img->dpy_depth );
	
	img->icn_gc = XCreateGC(dpy, img->icn_window, gc_mask, &gc_values);
	icn_alloc = True;
    }	
    
    if ( new_pixmaps || icn_alloc )
	check_pixmap_allocation( img );

    if ( new_window )
    {
	if ( img->icn_pixmap && img->icn_window ) {
	    wm_hints.flags = ( StateHint | IconPixmapHint | IconMaskHint |
			       IconWindowHint );
	    wm_hints.initial_state = NormalState;
	    wm_hints.icon_pixmap = img->icn_pixmap;
	    wm_hints.icon_window = img->icn_window;
	    wm_hints.icon_mask = img->icn_pixmap;
	
	    XSetWMHints (dpy, img->window, &wm_hints);
	}
	
	XSetWindowBackgroundPixmap(dpy, img->icn_window, img->icn_pixmap);
	
	XMapWindow( dpy, img->window );
	XClearWindow( dpy, img->window );

	get_cursors( img->window );
    }
    
    XFlush( dpy );
}

/* this is a relic */
static int		log2_levels;

/*
 * This routine builds the color map (for X window system, details may
 * differ in your system.  Note particularly the two level color
 * mapping:  X will give back 216 color map entries, but there is no
 * guarantee they are sequential.  The dithering code above wants to
 * compute a number in 0 - 215, so we must map from this to the X color
 * map entry id.
 */

/*
 * Initialize the 8 bit color map.  Use gamma corrected map.
 */

#define	IS_BINARY	1
#define	IS_MONO		2
#define	WANT_READ_WRITE	4
#define NOT_BINARY 	0
#define NOT_MONO 	0
#define	WANT_READ_ONLY	0

void init_color( img )
register image_information *img;
{
    register int	type;
    Boolean	done = False, try_ro = True;
    
    while ( ! done ) {
	DPRINTF (stderr, "Cmap type: binary %d, mono %d, read/write %d\n",
		 img->binary_img, img->mono_img, img->rw_cmap );

	type = ((( img->binary_img ) ? IS_BINARY : NOT_BINARY ) |
		(( img->mono_img ) ? IS_MONO : NOT_MONO ) | 
		((( img->rw_cmap && img->sep_colors ) ||
		  ( img->rw_cmap && !try_ro)) ?
		 WANT_READ_WRITE : WANT_READ_ONLY ));
	
	switch ( type ) {
	    
	case NOT_BINARY | NOT_MONO | WANT_READ_WRITE:
	    done = (( img->sep_colors ) ?
		    init_separate_color_rw( img ) :
		    init_color_rw( img ));
	    if ( !done && !try_ro) {
		fprintf( stderr,
			"%s: not enough cmap entries available, trying b/w.\n",
			 progname );
		img->mono_img = True;
		img->dpy_channels = 1;
	    }
	    break;
	    
	case NOT_BINARY | NOT_MONO | WANT_READ_ONLY:
	    done = (( img->sep_colors ) ?
		    init_separate_color_ro( img, try_ro ) :
		    init_color_ro( img, try_ro ));
	    if ( !done && !try_ro ) {
		fprintf( stderr,
			"%s: not enough cmap entries available, trying b/w.\n",
			 progname );
		img->mono_img = True;
		img->dpy_channels = 1;
	    }
	    break;
	    
	case NOT_BINARY | IS_MONO | WANT_READ_WRITE:
	    done = (img->sep_colors ?
		    init_separate_color_rw( img ) : init_mono_rw( img ));
	    if ( !done & !try_ro ) img->binary_img = True;
	    break;

	case NOT_BINARY | IS_MONO | WANT_READ_ONLY:
	    done = ( img->sep_colors ?
		    init_separate_color_ro( img, try_ro ) :
		    init_mono_ro( img, try_ro ));
	    if ( !done & !try_ro ) img->binary_img = True;
	    break;
	    
	case IS_BINARY | IS_MONO | WANT_READ_ONLY:
	    /* make the magic square */
	    get_dither_arrays( img );
	    make_square( 255.0, img->divN, img->modN, img->dm16 );

	    if ( img->pixel_table == NULL )
		img->pixel_table = (Pixel *) malloc (2 * sizeof (Pixel));
	    if (img->pixel_table == NULL) {
		perror ("malloc pixel_table (2)");
		exit (1);
	    }

	    do {
		Pixel wp = WhitePixel (dpy, screen);
		Pixel bp = BlackPixel (dpy, screen);
		if (bp < 2 && wp < 2) {
		    img->pixel_table[bp] = bp;
		    img->pixel_table[wp] = wp;
		}
		else {
		    img->pixel_table[0] = bp;
		    img->pixel_table[1] = wp;
		}
	    } while (0);
	    
	    img->lvls = 2;
	    img->lvls_squared = 4;
	    done = True;    
	    break;
	    
	default:
	    fprintf (stderr, "Unknown type in init_colors: %d\n", type);
	    exit (1);
	}
	if (! done) {
	    try_ro = False;
	    if ( img->rw_cmap == True ) {
		get_x_colormap( img );
	    }
	}
    }
    
    VPRINTF (stderr, "Created color map with %d entries", img->lvls);
    
    if (! img->mono_img ) {
	VPRINTF (stderr, " per color, %d total\n", img->lvls * img->lvls * img->lvls);}
    else VPRINTF (stderr, "\n");
    
    if ( img->binary_img )
    {
	black_pixel = BlackPixel (dpy, screen);
	white_pixel = WhitePixel (dpy, screen);
    }
    else if ( img->pixel_table != NULL ) {
	black_pixel = img->pixel_table[0];
	white_pixel = img->pixel_table[(img->mono_img) ? img->lvls - 1 :
				       img->lvls * img->lvls * img->lvls - 1];
    }
    else {
	black_pixel = 0;
	white_pixel = SHIFT_MASK_PIXEL(img->lvls - 1,img->lvls - 1,img->lvls - 1);
    }

}

static
Boolean
init_separate_color_rw ( img )
image_information *img;
{
    /*
     * use XAllocColorPlanes to allocate all the cells we need --
     * this makes it simple for me.
     */
    
#ifdef THIS_CODE_IS_NEVER_CALLED
    pixel_table = NULL;
    map = NULL;
    color_defs = NULL;
    
    DPRINTF (stderr, "In init_separate_color_rw \n");
    
    for (log2_num_lvls = log2_levels; 
	 log2_num_lvls >= 1; 
	 log2_num_lvls-- ) {
	
	num_lvls = 1 << log2_num_lvls;
	total_levels =  1 << (log2_num_lvls * 3);
	
	if (map == NULL) {
	    map = (int *) malloc (num_lvls * sizeof (int) );
	    if (map == NULL) continue;
	}
	
	if (color_defs == NULL) {
	    color_defs = (XColor *) malloc (num_lvls * sizeof (XColor) );
	    if (color_defs == NULL)
		continue;
	}
	
	if ( XAllocColorPlanes (dpy, img->colormap, 1, &pixel_base, 1,
				log2_num_lvls, log2_num_lvls,
				log2_num_lvls,
				&red_mask, &green_mask, &blue_mask) == 0)
	    continue;
	
	if (log2_num_lvls == 8) img->dither_img = False;
	
	bwdithermap ( num_lvls, display_gamma, map, divN, modN, dm16 );
	
	red_shift   = shift_match_right(red_mask);
	green_shift = shift_match_right(green_mask);
	blue_shift  = shift_match_right(blue_mask);
	
	/* 
	 * Set up the color map entries.
	 */
	
	for (i = 0; i < num_lvls; i++) {
	    color_defs[i].pixel = SHIFT_MASK_PIXEL(i, i, i);
	    
	    color_defs[i].red   = map[i] << 8;
	    color_defs[i].green = map[i] << 8;
	    color_defs[i].blue  = map[i] << 8;
	    
	    color_defs[i].flags = DoRed | DoGreen | DoBlue;
	}
	
	XStoreColors (dpy, img->colormap, color_defs, num_lvls);
	
	if (img->lvls > num_lvls) {
	    img->lvls = num_lvls;
	    img->lvls_squared = num_lvls * num_lvls;
	    log2_levels = log2_num_lvls;
	}
	
	free (map);
	free (color_defs);
	
	return (True);
	
    }
#endif /* THIS_CODE_IS_NEVER_CALLED */
    return (False);
}

/*
 * Used for allocating the colormap in a PsuedoColor visual or other color
 * type. Used for the standard 8 bit display
 */
static
Boolean
init_color_rw ( img )
image_information *img;
{
    int	num_lvls;
    int *map;
    XColor *color_defs, *color;
    int total_levels;
    int	red_index;
    int	green_index;
    int	blue_index;
    int	i, j;
    int free_pixels = 0, shift, cmap_size;
    Pixel *pixels;
    
    DPRINTF(stderr, "In init_color_rw\n");
    
    /* get free pixels from the default colormap */
    cmap_size = (1 << img->dpy_depth);

    /* get all free cells in the colormap in <depth> calls to AllocColor */
    pixels = (Pixel *) malloc (cmap_size * sizeof (Pixel) );
    color_defs = (XColor *) malloc (cmap_size * sizeof (XColor) );
    if ( pixels && color_defs )
    {
	DPRINTF(stderr, "Allocating colors: success/failure ");
	for (shift = img->dpy_depth; shift >= 0; shift--)
	    if (XAllocColorCells (dpy, img->colormap, False, 0, 0,
				  &pixels[free_pixels],
				  (int)1 << shift))
	    {
		DPRINTF(stderr, "1");
		free_pixels += (unsigned int)1 << shift;
	    }
	    else DPRINTF(stderr, "0");
	DPRINTF(stderr, " got %d\n", free_pixels);
    }

    for (num_lvls = img->lvls; 
	 num_lvls > 1; 
	 num_lvls-- )
    {
	total_levels =  num_lvls * num_lvls * num_lvls;
	if ( total_levels <= free_pixels )
	    break;
    }
    if ( !num_lvls )
	return (False);
    
    if (img->lvls > num_lvls) {
	img->lvls = num_lvls;
	img->lvls_squared = num_lvls * num_lvls;
	for (log2_levels = 1, i = 2; i < img->lvls; i <<= 1, log2_levels++) {
	    /* do nothing */
	}
    }
    
    if ( num_lvls == 256 )
	img->dither_img = False;
    
    if (! img->pixel_table )
	img->pixel_table = (Pixel *) malloc (total_levels * sizeof (Pixel) );

    map = (int *) malloc (num_lvls * sizeof (int) );
    
    if ( get_dither_arrays( img ) )
	bwdithermap ( num_lvls, display_gamma, map,
		      img->divN, img->modN, img->dm16 );
    
    /*
     * Use the top free_pixels NOT the bottom ones.  This makes it right for
     * 99% of the DISPLAYs out there which begin using colors at the bottom.
     * We take the top color cells, and copy the bottom ones into the extra
     * spaces, *some* other windows won't be clobbered by our colormap.
     */
    shift = free_pixels - total_levels;

    for (j = 0, i = shift; j < total_levels; i++, j++)
	img->pixel_table[j] = pixels[i];

    for (i = 0; i < shift; i++)
	color_defs[i].pixel = pixels[i];
    
    XQueryColors( dpy, DefaultColormap(dpy, screen),
		  color_defs, shift );

    /* 
     * Set up the color map entries.
     */
    
    color = &color_defs[shift];

    red_index = 0;
    green_index = 0;
    blue_index = 0;
	
    for (i = 0; i < total_levels; i++) {
	color->pixel = img->pixel_table[i];
	color->red   = map[red_index] << 8;
	color->green = map[green_index] << 8;
	color->blue  = map[blue_index] << 8;
	
	color->flags = DoRed | DoGreen | DoBlue;
	color++;
	
	if (++red_index >= num_lvls) {
	    if (++green_index >= num_lvls) {
		++blue_index;
		green_index = 0;
	    }
	    red_index = 0;
	}
	    
    }
	
    XStoreColors (dpy, img->colormap, color_defs, free_pixels);
    
    free (map);
    free (color_defs);
    free (pixels);
    return (True);
}

static
Boolean
init_separate_color_ro ( img, try_ro )
image_information *img;
int try_ro;
{
    register int	num_lvls;
    register int	log2_num_lvls;
    register int	*map = NULL;
    register int	i;
    
    DPRINTF(stderr, "In init_separate_color_ro\n");
    
    for (log2_num_lvls = log2_levels; 
	 log2_num_lvls >= 1; 
	 log2_num_lvls-- ) {
	
	num_lvls = 1 << log2_num_lvls;
	
	if (map == NULL) {
	    map = (int *) malloc (num_lvls * sizeof (int) );
	    if (map == NULL) continue;
	}
	
	if (num_lvls == 256) img->dither_img = False;
	
	get_dither_arrays( img );
	bwdithermap( num_lvls, display_gamma, map,
		    img->divN, img->modN, img->dm16 );
	
	red_mask   = img->dpy_visual->red_mask;
	green_mask = img->dpy_visual->green_mask;
	blue_mask  = img->dpy_visual->blue_mask;
	
	red_shift   = shift_match_left (red_mask, log2_num_lvls);
	green_shift = shift_match_left (green_mask, log2_num_lvls);
	blue_shift  = shift_match_left (blue_mask, log2_num_lvls);
	
	if (img->lvls > num_lvls) {
	    img->lvls = num_lvls;
	    img->lvls_squared = num_lvls * num_lvls;
	    log2_levels = log2_num_lvls;
	}
	
	/* pack into a pixel the pre shifted and maksed pixel values */
	if ( img->mono_color ) {
	    img->pixel_table = (Pixel *)malloc(img->cmlen * sizeof (Pixel));
	    if (!img->pixel_table) continue;
	    for ( i = 0; i < img->cmlen; i++ )
		img->pixel_table[i] =
		    SHIFT_MASK_PIXEL(img->in_cmap[RLE_RED][i],
				     img->in_cmap[RLE_GREEN][i],
				     img->in_cmap[RLE_BLUE][i]);
	}

	if ( map )
	    free (map);
	
	return (True);
	
    }
    
    return (False);
    
}

static int pixcompare(pixel1, pixel2 )
Pixel *pixel1, *pixel2;
{
    return( *pixel1 - *pixel2 );
}

void free_unique_colors( img, pixels, npixels )
image_information *img;
Pixel *pixels;
int npixels;    
{
    Pixel last, *p;
    int i, nunique;	

    if ( no_color_ref_counts )
    {
	qsort(pixels, npixels, sizeof(Pixel), pixcompare);
	p = pixels;

	for (i=1; i<npixels; i++ ) {
	    if ( pixels[i] != *p ) {
		p += 1;
		*p = pixels[i];
	    }
	}

	nunique = (p - pixels) + 1;

	DPRINTF(stderr, "In free_unique_pixels \n\nPixels: ");
	for (i=0;i<nunique;i++) DPRINTF(stderr, " %d ",pixels[i]);
	DPRINTF(stderr, "\n");
    }
    else
	nunique = npixels;

    XFreeColors(dpy, img->colormap, pixels, nunique, 0);
}

static
Boolean
init_color_ro ( img, try_ro )
image_information *img;
int try_ro;
{
    register int	num_lvls;
    register int	total_levels;
    XColor		color_def;
    register XColor	*color_defs = NULL;
    register Status 	*status = NULL;
    register int	red_index;
    register int	green_index;
    register int	blue_index;
    register int	*map = NULL;
    register int	i,j;
    int first = True;
    
    DPRINTF(stderr, "In init_color_ro\n");
    
    for (num_lvls = img->lvls; num_lvls >= 2; num_lvls -- ) {
	
	if (try_ro && !first && specified_levels) break;
	else first = False;
	
	total_levels = num_lvls * num_lvls * num_lvls;
	
	if ( !img->pixel_table ) {
	    img->pixel_table = (Pixel *)malloc(total_levels * sizeof (Pixel) );
	    if ( !img->pixel_table ) continue;
	}
	
	if ( map == NULL ) {
	    map = (int *) malloc (num_lvls * sizeof (int) );
	    if (map == NULL) continue;
	}
	
	if (num_lvls == 256) img->dither_img = False;
	
	get_dither_arrays( img );
	bwdithermap( num_lvls, display_gamma, map,
		    img->divN, img->modN, img->dm16 );

	/* try to get a color map entry for each color. */
	red_index = green_index = blue_index = 0;
	
#ifdef XLIBINT_H_NOT_AVAILABLE
	for ( i = 0; i < total_levels; i++ ) {
	    color_def.red   = map[red_index] << 8;
	    color_def.green = map[green_index] << 8;
	    color_def.blue  = map[blue_index] << 8;
	    
	    if ( XAllocColor (dpy, img->colormap, &color_def ) == 0 ) {
		break;
	    }
	    
	    if (++red_index >= num_lvls) {
		if (++green_index >= num_lvls) {
		    ++blue_index; green_index = 0;
		}
		red_index = 0;
	    }
	    
	    img->pixel_table[i] = color_def.pixel;
	}
	
	/* Check if the colors are available */
	if ( i < total_levels ) { 	/* Free the colors already obtained */
	    free_unique_colors (img, img->pixel_table, i );
	    continue;
	}
#else
	if (!color_defs)
	    color_defs = (XColor *) malloc(total_levels * sizeof (XColor));
	if (!status)
	    status = (Status *) malloc(total_levels * sizeof (Status));
	if ( !status || !color_defs ) continue;

	for ( i = 0; i < total_levels; i++ ) {
	    color_defs[i].red   = map[red_index] << 8;
	    color_defs[i].green = map[green_index] << 8;
	    color_defs[i].blue  = map[blue_index] << 8;
	    if (++red_index >= num_lvls) {
		if (++green_index >= num_lvls) {
		    ++blue_index; green_index = 0;
		}
		red_index = 0;
	    }
	}
	    
	if (XAllocColors(dpy, img->colormap, color_defs, total_levels, status)== 0)
	{
	    for ( i = 0, j = 0; i < total_levels; i++ )
		if (status[i])
		    img->pixel_table[j++] = color_defs[i].pixel;
	    free_unique_colors (img, img->pixel_table, j );
	    continue;
	} else
	    for ( i = 0; i < total_levels; i++ )
		img->pixel_table[i] = color_defs[i].pixel;		
	
#endif	
	img->lvls = num_lvls;
	img->lvls_squared = num_lvls * num_lvls;
	
	for (log2_levels = 1, i = 2; i < img->lvls; i <<= 1, log2_levels++) {
	    /* do nothing */
	}
	if (map) free (map);
	if (status) free (status);
	if (color_defs) free (color_defs);
	return (True);
    }
    if (map) free (map);
    if (status) free (status);
    if (color_defs) free (color_defs);
    return (False);
}

static
Boolean
init_mono_rw ( img )
image_information *img;
{
    int	num_lvls;
    int	*map;
    XColor *color_defs, *color;
    int	i, j;
    int free_pixels = 0, shift, cmap_size;
    Pixel *pixels;
    
    DPRINTF(stderr, "In init_mono_rw\n");
    
    /* get free pixels from the default colormap */
    cmap_size = (1 << img->dpy_depth);

    /* get all free cells in the colormap in <depth> calls to AllocColor */
    pixels = (Pixel *) malloc (cmap_size * sizeof (Pixel) );
    color_defs = (XColor *) malloc (cmap_size * sizeof (XColor) );
    if ( pixels && color_defs ) {
	DPRINTF(stderr, "Allocating colors: success/failure ");
	for (shift = img->dpy_depth; shift >= 0; shift--)
	    if (XAllocColorCells (dpy, img->colormap, False, 0, 0,
				  &pixels[free_pixels],
				  (int)1 << shift))
	    {
		DPRINTF(stderr, "1");
		free_pixels += (unsigned int)1 << shift;
	    }
	    else DPRINTF(stderr, "0");
	DPRINTF(stderr, " got %d\n", free_pixels);
    }

    if ( img->mono_color ) {
	img->lvls = img->cmlen;
	if ( img->cmlen > free_pixels )
	    fprintf(stderr, "%s: Warning: Not enough cells for input cmap\n",
		    progname);
    }

    if ( free_pixels == 0 ) return False;

    num_lvls = img->lvls;
    while ( num_lvls > free_pixels && num_lvls >= 2 )
	num_lvls = ((num_lvls > 16) ? num_lvls / 2 : num_lvls - 1);

    img->lvls = num_lvls;
    img->lvls_squared = num_lvls * num_lvls;
    for (log2_levels = 1, i = 2; i < img->lvls; i <<= 1, log2_levels++) {
	/* do nothing */
    }
    
    if ( num_lvls == 256 && img->mono_color )
	img->dither_img = False;

    if ( !img->pixel_table )
	img->pixel_table = (Pixel *)
	    malloc ((img->mono_color? img->cmlen : num_lvls) * sizeof(Pixel) );
    map = (int *) malloc ( num_lvls * sizeof(int) );

    if (!map || !img->pixel_table)  {
	fprintf(stderr, "malloc problems in init_mono_rw\n");
	return False;
    }

    get_dither_arrays( img ); 
    bwdithermap(num_lvls, display_gamma, map,
		img->divN, img->modN, img->dm16 );
    
    /*
     * Use the top free_pixels NOT the bottom ones.  This makes it right for
     * 99% of the DISPLAYs out there which begin using colors at the bottom.
     * We take the top color cells, and copy the bottom ones into the extra
     * spaces, *some* other windows won't be clobbered by our colormap.
     */
    shift = free_pixels - num_lvls;

    for (j = 0, i = shift; j < num_lvls; i++, j++)
	img->pixel_table[j] = pixels[i];

    for (i = 0; i < shift; i++)
	color_defs[i].pixel = pixels[i];
    
    XQueryColors( dpy, DefaultColormap(dpy, screen), color_defs, shift );

    /* 
     * Set up the color map entries.
     */

    color = &color_defs[shift];

    if (img->mono_color)
	for ( i = 0; i < num_lvls; i++ ) {
	    color->pixel = img->pixel_table[i];
	    color->red = img->in_cmap[RLE_RED][i] << 8;
	    color->green = img->in_cmap[RLE_GREEN][i] << 8;
	    color->blue = img->in_cmap[RLE_BLUE][i] << 8;
	    color->flags = DoRed | DoGreen | DoBlue;
	    color++;
	}
    else
	for ( i = 0; i < num_lvls; i++ ) {
	    color->pixel = img->pixel_table[i];
	    color->red = map[i] << 8;
	    color->green = map[i] << 8;
	    color->blue = map[i] << 8;
	    color->flags = DoRed | DoGreen | DoBlue;
	    color++;
	}

    XStoreColors (dpy, img->colormap, color_defs, free_pixels);

    free (map);
    free (color_defs);
    free (pixels);
    return (True);
}

static
Boolean
init_mono_ro ( img, try_ro )
image_information *img;
int try_ro;
{
    register int		num_lvls;
    XColor			color_def;
    register XColor		*color_defs = NULL;
    register Status 		*status = NULL;

    register int		* map = NULL;
    register int		i,j;
    int first = True;
    
    DPRINTF(stderr, "In init_mono_ro");
    if ( try_ro ) {
	DPRINTF(stderr, " trying read/only\n");
    } else {
	DPRINTF(stderr, "\n");
    }
    
    if ( img->mono_color ) 
	img->lvls = img->cmlen;

    for (num_lvls = img->lvls; num_lvls >= 2; 
	 num_lvls = (num_lvls > 16) ? num_lvls / 2 : num_lvls - 1 ) {
	
	if ( try_ro && !first && specified_levels ) break;
	else if ( !first && img->mono_color ) break;
	else first = False;
	
	if (img->pixel_table == NULL) {
	    img->pixel_table = (Pixel *) malloc (num_lvls * sizeof (Pixel) );
	    if (img->pixel_table == NULL) continue;
	}
	
	if (map == NULL) {
	    map = (int *) malloc (num_lvls * sizeof (int) );
	    if (map == NULL) continue;
	}
	
	if (num_lvls == 256 || img->mono_color)
	    img->dither_img = False;
	
	get_dither_arrays( img );
	bwdithermap(num_lvls, display_gamma, map,
		    img->divN, img->modN, img->dm16 );
	
	/* try to get a color map entry for each color.  */
	
#ifdef XLIBINT_H_NOT_AVAILABLE
	for ( i = 0; i < num_lvls; i++ ) {
	    if ( img->mono_color ) {
		color_def.red   = img->in_cmap[RLE_RED][i] << 8;
		color_def.green = img->in_cmap[RLE_GREEN][i] << 8;
		color_def.blue  = img->in_cmap[RLE_BLUE][i] << 8;
	    } else {
		color_def.red   = map[i] << 8;
		color_def.green = map[i] << 8;
		color_def.blue  = map[i] << 8;
	    }
	    
	    if ( XAllocColor (dpy, img->colormap, &color_def ) == 0 ){ 
		break;
	    }
	    img->pixel_table[i] = color_def.pixel;
	}
	
	/* Check if the colors are available */
	
	if ( i < num_lvls) {
	    /* Free the colors already obtained */
	    
	    free_unique_colors (img, img->pixel_table, i );
	    continue;		/* adjust level & repeat */
	}
#else
	if (!color_defs)
	    color_defs = (XColor *) malloc(num_lvls * sizeof (XColor));
	if (!status)
	    status = (Status *) malloc(num_lvls * sizeof (Status));
	if ( !status || !color_defs ) continue;

	for ( i = 0; i < num_lvls; i++ ) {
	    color_defs[i].pixel = 0;
	    if ( img->mono_color ) {
		color_defs[i].red   = img->in_cmap[RLE_RED][i] << 8;
		color_defs[i].green = img->in_cmap[RLE_GREEN][i] << 8;
		color_defs[i].blue  = img->in_cmap[RLE_BLUE][i] << 8;
	    } else {
		color_defs[i].red   = map[i] << 8;
		color_defs[i].green = map[i] << 8;
		color_defs[i].blue  = map[i] << 8;
	    }
	}
	    
	if (XAllocColors(dpy, img->colormap, color_defs, num_lvls, status)== 0)
	{
	    for ( i = 0, j = 0; i < num_lvls; i++ )
		if (status[i])
		    img->pixel_table[j++] = color_defs[i].pixel;
	    free_unique_colors (img, img->pixel_table, j );
	    continue;
	} else
	    for ( i = 0; i < num_lvls; i++ )
		img->pixel_table[i] = color_defs[i].pixel;		
	
#endif
	img->lvls = num_lvls;
	img->lvls_squared = num_lvls * num_lvls;
	
	for (log2_levels = 1, i = 2; i < img->lvls; i <<= 1, log2_levels++);
	/* do nothing */

	free (map);
	if (status) free (status);
	if (color_defs) free (color_defs);
	return (True);
	
    }
    if (img->pixel_table)
	free (img->pixel_table);
    img->pixel_table = NULL;

    if (map) free (map);
    if (status) free (status);
    if (color_defs) free (color_defs);
    return (False);
}


static CONST_DECL char *visual_class_to_string(visual_type)
    int visual_type;
{
    CONST_DECL char *type_string;
    switch (visual_type) {
    case DirectColor:	type_string = "DirectColor";	break;
    case PseudoColor:	type_string = "PseudoColor";	break;
    case TrueColor:	type_string = "TrueColor";	break;
    case StaticColor:	type_string = "StaticColor";	break;
    case GrayScale:	type_string = "GrayScale";	break;
    case StaticGray:	type_string = "StaticGray";	break;
    default: 		type_string = "any/unknown";	break;
    }
    return type_string;
}

#define BINARY_TABLE_INDEX	0
#define MONOCHROME_TABLE_INDEX	1
#define COLOR_TABLE_INDEX	2

/* Here we ALWAYS want to take a PseudoColor over the next best visual... */
/* in Monochrome, we can do just as much with a pseudo color visual, and   */
/* we may be able to preserve some of the default colors from other windows*/
/* In color mode, some eight bit displays offer a Direct and TrueColor     */
/* visual..   This is quite confusing, Have you ever seen a 24bit display  */
/* offer a 24-bit PseudoColor visual?  They offer 8 bit PC visuals usually */

static int desired_class_table [][6] = {
{ PseudoColor, StaticGray, GrayScale, DirectColor, TrueColor, StaticColor},
{ PseudoColor, GrayScale, StaticGray, DirectColor, TrueColor, StaticColor},
{ PseudoColor, DirectColor, TrueColor, StaticColor, GrayScale, StaticGray}
};

void
find_appropriate_visual( img )
register image_information *img;
{
    static int			num_visuals = 0;
    static XVisualInfo		*visual_info = NULL;
    register XVisualInfo	*vi, *found_vi;
    XVisualInfo			*XGetVisualInfo ();
    VisualID			def_visual_id;
    int				def_visual_index;
    int				def_scrn = DefaultScreen(dpy);
    int				desired_class;
    int				desired_depth;
    int 			deepest_visual;
    int				depth_delta;
    register int		i;
    
    DPRINTF(stderr, "In find_appropriate_visual(%d)\n", img->img_channels);
    
    if (visual_info == NULL) {
	visual_info = XGetVisualInfo (dpy, VisualNoMask, NULL, &num_visuals);
	if (visual_info == NULL || num_visuals == 0) {
	    fprintf (stderr, "XGetVisualInfo failed\n");
	    exit (1);
	}	    
    }
    
    desired_depth = 1;
    
    for (i = 2; i < img->lvls; i <<= 1) {
	desired_depth++;
    }
    
    if ( img->mono_img && img->lvls == 2 )
	img->binary_img = True;
    
    if ( img->binary_img ) {
	desired_class = BINARY_TABLE_INDEX;
	desired_depth = 1;
	depth_delta = 1;
    }
    else if ( img->mono_img ) {
	desired_class = MONOCHROME_TABLE_INDEX;
	depth_delta = 1;
    }
    else {
	desired_class = COLOR_TABLE_INDEX;
	desired_depth *= 3;		/* needed if separate colors	*/
	depth_delta = 3;
    }
    
    VPRINTF (stderr, "Searching for %s visual with desired depth >= %d\n", 
	     visual_class_to_string(img->visual_class), desired_depth);
    
    /*
     * find visual such that:
     *
     *	1. depth is as large as possible (up to true desired depth)
     *	2. visual depth is the smallest of those supported >= depth
     *	3. visual class is the `most desired' for the image type
     *		Meaning! that if it is the DefaultVisual it IS the
     *		most desired.  We can't choose one visual class over
     *		another for all displays!  If the depth of the DefaultVisual
     *		is large enough for the image, or as large as all others, we
     *		use it!  This minimizes screw ups on our part.
     */
    
    found_vi = NULL;
    
    def_visual_id = DefaultVisual(dpy, def_scrn)->visualid ;
    deepest_visual = 0;
    
    for (i = 0; i < num_visuals; i++)
    {
	if ( deepest_visual < visual_info[i].depth )
	    deepest_visual = visual_info[i].depth;
	
	if ( def_visual_id == visual_info[i].visualid )
	    def_visual_index = i;
    }
    
    /* Take the Default Visual if it's cool enough... */
    if ( visual_info[def_visual_index].depth >= desired_depth ||
	 visual_info[def_visual_index].depth == deepest_visual )
	found_vi = &visual_info[def_visual_index];
    
    /* if we were told to look for a specific type first, do it */
    if ( img->visual_class >= 0 ) {
	int depth;
	for (depth = desired_depth; depth >= 1; depth -= depth_delta) {
	    for (vi = visual_info; vi < visual_info + num_visuals; vi++) 
		if (vi->class == img->visual_class && vi->depth >= depth &&
		    vi->screen == def_scrn ) {
		    found_vi = vi;
		    
		    if (found_vi->depth == depth) break;
		}
	    if (found_vi != NULL && found_vi->class == img->visual_class)
		break;
	}
    }
    
    /* Werent told to get any type of Visual, or didn't find one, wingit */
    if ( img->visual_class < 0 ) {
	int depth;
	for (depth = desired_depth; depth >= 0; depth -= depth_delta) {
	    if (found_vi != NULL)
		break;
	    for (i = 0; i < 6; i++) {
		int vt;
		
		/* search for class and depth */
		vt = desired_class_table[desired_class][i];
		
		for (vi = visual_info; vi < visual_info+num_visuals; vi++)
		    if (vi->class == vt && vi->depth >= depth &&
			vi->screen == def_scrn ) {
			if (found_vi==NULL || found_vi->depth > vi->depth)
			    found_vi = vi;
			if (vi->depth == depth)
			    break;
		    }
	    }
	}
    }
    
    if (found_vi == NULL) {
	fprintf (stderr, "%s: Could not find appropriate visual type - %s\n",
		 progname, visual_class_to_string(img->visual_class));
	exit (1);
    }
    
    /* set program the_hdr */
    screen = found_vi->screen;
    root_window = RootWindow (dpy, screen);

    /* set img variables */
    img->dpy_depth = found_vi->depth;
    img->dpy_visual = found_vi->visual;
    img->visual_class = found_vi->class;

    /* We want to give the DefaultColormap a shot first */
    if ( found_vi->visualid == def_visual_id )
	img->colormap = DefaultColormap( dpy, screen );
    else
	get_x_colormap( img );
    
    if ( img->dpy_depth == 1 || img->binary_img ) {
	img->binary_img = True;
	img->mono_img = True;
	img->color_dpy = False;
	img->dpy_channels = 1;
	img->sep_colors = False;
	img->rw_cmap = False;
	
	img->lvls = 2;
	img->lvls_squared = 4;
	log2_levels = 1;
    }
    else {
	int class = img->visual_class;
	
	if ( class == GrayScale || class == StaticGray ) {
	    img->mono_img = True;
	    img->color_dpy = False;
	    img->dpy_channels = 1;
	    depth_delta = 1;
	}
	
	img->rw_cmap = (class == PseudoColor || class == GrayScale);
	
	if ( img->dpy_visual != DefaultVisual( dpy, screen ) )
	    img->colormap = XCreateColormap( dpy, root_window,
					     img->dpy_visual, AllocNone );

	if ( class == StaticColor || class == DirectColor || class == TrueColor ) {
	    img->sep_colors = True;
	    
	    i = 1 << (img->dpy_depth / depth_delta);
	    
	    if ( img->lvls > i) {
		img->lvls = i;
		img->lvls_squared = i * i;
	    }
	} else {
	    img->sep_colors = False;
	    
	    /* Image is monochrome??? */
	    if (depth_delta == 1) {
		i = found_vi->colormap_size;
	    }
	    else { /* color */
		for (i = 1; i * i * i < found_vi->colormap_size; i++) {}
		i--;
	    }
	    
	    if (img->lvls > i) {
		img->lvls = i;
		img->lvls_squared = i * i;
	    }
	}
	
	for (log2_levels = 1, i = 2; i < img->lvls; i <<= 1, log2_levels++);
	/* do nothing */
    }

    VPRINTF(stderr, "Visual type %s, depth %d, screen %d\n", 
	    visual_class_to_string(img->visual_class), img->dpy_depth, screen);
    
    VPRINTF(stderr, "levels: %d, log(2) levels: %d\n", img->lvls, log2_levels);
}

static XFontStruct *pixel_font_info = NULL;

void
MapPixWindow ( img, use_top )
image_information *img;
int use_top;
{
    Window hukairz;
    int x, y;
    unsigned int w, h, hunoz, huwanz, font_height;

    XGetGeometry (dpy, img->window, &hukairz, &x, &y, &w, &h, &hunoz, &huwanz);

    if (!pixel_font_info) {
	pixel_font_info = XLoadQueryFont (dpy, "fixed");
	if (!pixel_font_info) {
	    fprintf (stderr, "%s: unable to load font '%s'\n",
		     progname, "fixed");
	    exit (1);
	}
    }

    font_height = pixel_font_info->ascent + pixel_font_info->descent + 4;
    y = (use_top ? 0 : (h - font_height));

    if ( img->pix_info_window == NULL ) {
	XSetFont (dpy, img->gc, pixel_font_info->fid );
	img->pix_info_window = XCreateSimpleWindow
	    (dpy, img->window, 0, y, w, font_height, 0, None, black_pixel );
    }
    else 
	XMoveResizeWindow ( dpy, img->pix_info_window, 0, y, w, font_height );

    XMapWindow ( dpy, img->pix_info_window );
}

void
DrawPixWindow ( img, x, y )
image_information *img;
int x, y;
{
    char str[256];
    unsigned char *r, *g, *b;

    r = SAVED_RLE_ROW( img, y ) + x;

    switch ( img->dpy_channels ) {
    case 1:
	if ( img->mag_fact > 1 )
	    sprintf (str, "(%4d,%4d): ( %3d ) (Mag %2d)",
		     x + img->x, img->h - y - 1 + img->y,
		     *r, img->mag_fact);
	else
	    sprintf (str, "(%4d,%4d): ( %3d )",
		     x + img->x, img->h - y - 1 + img->y, *r);
	break;
    case 2:
	g = r + img->w;
	if ( img->mag_fact > 1 )
	    sprintf (str, "(%4d,%4d): ( %3d, %3d ) (Mag %2d)",
		     x + img->x, img->h - y - 1 + img->y,
		     *r, *g, img->mag_fact);
	else
	    sprintf (str, "(%4d,%4d): ( %3d, %3d )",
		     x + img->x, img->h - y - 1 + img->y,
		     *r, *g);
	break;
    case 3:
	g = r + img->w;
	b = g + img->w;
	if ( img->mag_fact > 1 )
	    sprintf (str,
		     "(%4d,%4d): 0x%02x%02x%02x ( %3d, %3d, %3d ) (Mag %2d)",
		     x + img->x, img->h - y - 1 + img->y,
		     *r, *g, *b, *r, *g, *b, img->mag_fact);
	else
	    sprintf (str, "(%4d,%4d): 0x%02x%02x%02x ( %3d, %3d, %3d )",
		     x + img->x, img->h - y - 1 + img->y,
		     *r, *g, *b, *r, *g, *b);
	break;
    }

    XClearWindow ( dpy, img->pix_info_window );
    XDrawString ( dpy, img->pix_info_window, img->gc,
		  4, 2 + pixel_font_info->ascent, str, strlen (str) );
}

void
DrawSpeedWindow ( img, s )
image_information *img;
int s;
{
    char str[256];
    
    if ( s > 0 ) 
	sprintf( str, "%s%d Frames/Second", (s > 0) ? "": "1/", (s>0)?s:-s );
    else 
	sprintf( str, "As fast as possible" );

    XClearWindow ( dpy, img->pix_info_window );
    XDrawString ( dpy, img->pix_info_window, img->gc,
		  4, 2 + pixel_font_info->ascent, str, strlen (str) );
}


void
UnmapPixWindow( img )
image_information *img;
{
    XUnmapWindow ( dpy, img->pix_info_window );
}

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