Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://xcol-1.7.tgz:19840/xcol-1.7/xcol.c  downloads

/****************************************************************
 *								*
 *  xcol - program to edit color-name-occurrences in textfiles	*
 *								*
 *	     Written by Helmut Hoenig, Feb. 1990.		*
 *	    University of Kaiserslautern, Germany		*
 *								*
 ****************************************************************
 *                                                              *
 *              additinal changes: Sep. 1995.			*
 *              e-mail: Helmut.Hoenig@hub.de			*
 *								*
 ****************************************************************/

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>

#include <sys/param.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>

/*----------------------------------------------------------------------------*/

#define	COLOR_FONT	"-adobe-times-bold-r-normal--18-*-iso8859-1"
#define	TEXT_FONT	"-adobe-times-bold-r-normal--12-*-iso8859-1"
#define DEFAULT_FONT	"-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1"

#define	RGB_FILE	"/usr/lib/X11/rgb.txt"

/* MAX_??? - definitions are used in the definition of some local arrays, 
   where I didn't want to make complicated memory allocation.		*/

#define	MAX_CELLS	256	/* number of cells, used by the programm*/

#define	MAX_COLS	1000	/* colors in rgb.txt-file		*/
#define	MAX_COLOR_LINES	400	/* color occurrences in a textfile	*/
#define	MAX_LINE_LENGTH	1000	/* linelength of textfile		*/

/*----------------------------------------------------------------------------*/

/* switch on/off some bugs ?? */
#define	CHG_TEXT_WINDOW_COLORMAP
#define _RECOLOR_CURSOR

/* variables for parameters (default is set) */
int		reverse	= 0;
int		BO_def	= 0;
int		darkness=50;
int		gran	=11;
int		original= 0;

/* X-Data */
Display		*display;
Screen		*screen;
XFontStruct	*finfo;
GC		gc;
int		cells;

/* the grey-pixmap is used to get an impression of mixing the foreground
 * and background color of a color-line.
 */
#define grey_width 16
#define grey_height 16
static char grey_bits[] = {
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
Pixmap	grey_pixmap;

Cursor	mw_cursor;	/* Cursor in main-window			*/
Cursor	tw_cursor;	/* Cursor in text-window			*/
Cursor	subsel_cursor;	/* Cursor during selection of associated colors */
Cursor	text_cursor;	/* Cursor while looking in the source-file	*/
Cursor	quest_cursor;	/* Cursor while asking for write-confirmation	*/
Cursor	updown_cursor;	/* Cursor while making association		*/

/* Mainwindow-Data */
Window		mw;	/* Window-Id */
unsigned int	dx, dy;	/* current size of the window */
int		BO=14;	/* current size of the color-boxes in the window */

/* Textwindow-Data */
Window		tw = 0;
XFontStruct	*tinfo;			/* Structure of the textfont */
int		char_width, char_height;/* char-size depending on the font */
char		*tw_message[2];		/* messages in header and footer-line */
int		twidth;			/* width in pixel */
int		tw_lines;		/* height in lines (header&footer not included) */
int		act_line=0;		/* active-line */
int		act_offset=0;		/* first color-line (when not all lines fit in the window) */

/* Subwindow-Data (little window for selected color) */
Window		subw;		/* Window-Id */
int		sdx, sdy;	/* current size of subwindow */
int		subcols;	/* number of associated colors in the subwindow */

/* Color-Management */
Colormap	my_map=0;
int		my_pixel[MAX_CELLS];	/* flag: 0 = pixel not used in my program */
int		only_mine;	/* flag: 1 = allocations only in own map */

#define	NotAllocated	(-1L)
#define	Undefined	(-2L)

typedef	struct _color_def {
	int			r, g, b;	/* rgb-value from the 'rbg.txt'-file */
	char			*name;	/* name from the 'rgb.txt'-file */
	int			x, y;	/* position in main window	*/
	unsigned long		pixel;	/* allocated pixel for the color */
	struct	_color_def	*associated;	/* colors with different intensity (e.g. 'blue' -> 'blue4' ... ) */
	struct	_color_def	*brother;	/* colors with different name (e.g. 'OldLace' -> 'old lace') */
} ColorDef;

typedef	struct _color_strings {
	char		*name;
	int		length;
	ColorDef	*def;
} ColorString;

ColorDef	*color[MAX_COLS];	/* field with the definitions of the colors */
ColorString	cname[MAX_COLS];	/* sorted field with the names of all colors */
ColorString	*first[256];		/* 'Hash-Table', points to the first name
					   that starts with the given letter. */

int	color_names;	/* number of color-names
			   = entries in the 'rgb.txt'-file */
int	color_number;	/* number of 'different' colors
			   = number of colors shown in the cube */

#define	BLACK_STRING	"black"
#define	WHITE_STRING	"white"
#define	GREY_STRING	"gray"

ColorDef std_black = {   0,   0,   0, BLACK_STRING };
ColorDef std_white = { 255, 255, 255, WHITE_STRING };
ColorDef std_grey  = { 192, 192, 192, GREY_STRING  };

unsigned long	white, black, grey;	/* pixel-values (in my_map !!) */
ColorDef *back_def;			/* default background in textwindow */

/*----------------------------------------------------------------------------*/

typedef	struct	_text_line {	/* structure to store the text-file */
	char			*contents;
	struct	_text_line	*next;
	struct	_text_line	*previous;
} TextLine;

typedef	struct	_color_line {	/* structure for a line with color-entry */
	TextLine	*line;		/* pointer to the textline */	
	ColorDef	*color;		/* the color defined in the line */
	ColorDef	*help;		/* a help-color for the background */
	int		reverse;	/* flag to display line in reverse */
	int		pos_in_line;	/* position of the color-name in the line */
	int		assoc;		/* corresponding color-line, when a
					   'foreground-background'-association
					   was found (or entered) */
} ColorLine;

char		*file_name;		/* name of the text-file */
TextLine	*loaded_text;		/* Pointer to the first line */
ColorLine	line[MAX_COLOR_LINES];	/* array of the color-lines */
int		color_lines;		/* number of the color-lines */
int		longest_colored;	/* length of the longest color-line */

char	space_char[256];		/* flag, which chars should be recognized
					   as spaces */


/********************************************************************************
 *	    parsing the text-file (not very efficient, but who cares)		*
 ********************************************************************************/


void set_default_spaces()
{
	memset( space_char, 0, (int)sizeof(space_char) );
	space_char[ ' ' ] = space_char[ '\t' ] = space_char[ '\n' ] = 
	space_char[ ':' ] = space_char[ '"' ] = 1;
}

int strncase_equal( s1, s2, n )
	register char	*s1;
	register char	*s2;
	register int	n;
/* the function is NOT correct, since just proves, if strings are equal
   when the 5th bit of their characters is ignored.
 */
{
	while(n--)
	{	if ( ((*s1++)^(*s2++))&((unsigned char)~32) )	return(1);
	}
	return(0);
}

int strcase_equal( s1, s2 )
	char	*s1,*s2;
{
int	n1,n2;

	n1 = strlen(s1);
	n2 = strlen(s2);
	if (n1!=n2)	return(-1);
	else		return(strncase_equal( s1, s2, n1 ));
}

string_exchange( cline, new_color )
	ColorLine	*cline;
	ColorDef	*new_color;
/* replaces the color-string in a color-line */
{
char	new_line[MAX_LINE_LENGTH];
int	pos;

	pos = cline->pos_in_line;
	strncpy( &new_line[0], cline->line->contents, pos );
	strcpy( &new_line[pos], new_color->name );
	strcat( new_line, &cline->line->contents[pos+strlen(cline->color->name)] );
	free( cline->line->contents );
	cline->line->contents = (char *)malloc((unsigned) strlen( new_line )+1 );
	strcpy( cline->line->contents, new_line );
}

void check_colors( in_line )
	TextLine	*in_line;
/* checks, if a color exists in the given line and possibly adds
 * the line to the list of color-lines.
 */
{
int		i, c;
char		lett;
char		check;
ColorString	*col;
unsigned char	*act_line = in_line->contents;
int		alen;

	alen=c=strlen(act_line);
	while(c>0)
	{  
	   c--;
	   while( (c>0) && !(space_char[act_line[c-1]]))		c--;

	    lett = act_line[c];
	    if (isalpha(lett))
	    {
	    	if (isupper(lett))	lett = tolower( lett );
	/* compares both cases */
		for (i=0;i<2;i++)
		{    for (col=first[lett];col<first[lett+1];col++)
		    {
		    	check = (c+col->length<alen)?act_line[c+col->length]:0;
			if (space_char[check])
			{	if ((strncase_equal( &act_line[c], col->name, col->length )==0 ))
				{	line[color_lines].line = in_line;
					line[color_lines].color= col->def;
					line[color_lines].help = back_def;
					line[color_lines].pos_in_line = c;
					line[color_lines].reverse = 0;
					line[color_lines].assoc = -1;
					if (strstr(in_line->contents,"GlobalBackground")) {
							back_def = col->def;
							line[color_lines].assoc = -2;
					}

					if (original)
					{	string_exchange( &line[color_lines], col->def );
					}
					if (XTextWidth( tinfo, act_line, strlen(act_line) )>longest_colored)
						longest_colored = XTextWidth( tinfo, act_line, strlen(act_line) );
					color_lines++;
					return;
				}
			}
		    }
		    lett = toupper( lett );
		}
	    }
	}
}

int spc_line( search_string, line, name, length )
	char		*search_string;
	TextLine	*line;
	char		*name;
	int		*length;
/* searches for the search-string in the given line. If it exists, the name
 * in front of the search-string is copied to name and its length is returned.
 */
{
int	c, sl, cs;

	c = strlen( line->contents );
	sl = strlen(search_string);
	while( c>0 )
	{	if (strncase_equal( search_string, &line->contents[c], sl )==0)
		{	cs=c;
			do
			{	cs--;
				if (isspace(line->contents[cs]))	break;
			}
			while(cs>0);
			*length = c-cs;
			if (cs)
			{	(*length)--;	cs++;
			}

			strncpy( name, &line->contents[cs], *length );
			name[*length]='\0';
			return(1);
		}
		c--;
	}
	return(0);
}

void find_assocs()
/* tries to find 'Foreground-Background'-Associations in the Color-Lines */
{
int	i, j;
char	name1[100], name2[100];
int	length1, length2;

	for (i=0;i<color_lines;i++)
	{	if (spc_line("foreground", line[i].line, name1, &length1))
		{	for (j=i+1;j>=i-1;j-=2)
			{   if ((j>=0)&&(j<color_lines))
			    {	if (spc_line("background", line[j].line, name2, &length2))
				{
					if (strcmp(name1, name2)==0)
					{	line[i].reverse=0;
						line[i].help = line[j].color;
						line[i].assoc= j;

						line[j].reverse=1;
						line[j].help = line[i].color;
						line[j].assoc= i;
					}
				}
			    }
			}
		}
		else if ((spc_line("background", line[i].line, name1, &length1))&&(line[i].assoc<0))
		{	for (j=i+1;j>=i-1;j-=2)
			{   if ((j>=0)&&(j<color_lines))
			    {	if (spc_line("border", line[j].line, name2, &length2))
				{
					if (strcmp(name1, name2)==0)
					{	line[i].reverse=1;
						line[i].help = line[j].color;
						line[i].assoc= j;

						line[j].reverse=0;
						line[j].help = line[i].color;
						line[j].assoc= i;
					}
				}
			    }
			}
		}
	}
}

int load_file( fname )
	char	*fname;
/* loads the text-file and tries to find color-entries in each line */
{
FILE		*fp;
TextLine	*act, *next;
char		linebuffer[MAX_LINE_LENGTH];

/* load the file with colors */
	longest_colored = 0;
	color_lines = 0;

	fp = fopen( fname, "r" );
	if (fp==NULL)
	{	fprintf( stderr, "can't load file '%s'.\n", fname );
		return(0);
	}

	loaded_text = act = NULL;
	while (fgets( linebuffer, sizeof linebuffer, fp )!=NULL)
	{	next = (TextLine *)malloc((unsigned)sizeof(TextLine));
		next->contents = (char *)malloc((unsigned)strlen(linebuffer)+1);
		strcpy( next->contents, linebuffer );

		check_colors( next );
		if (act==NULL)
		{	loaded_text=act	= next;
			next->previous	= NULL;
		}
		else
		{	act->next	= next;
			next->previous	= act;
			act = next;
		}
	}
	fclose( fp );
	act->next=NULL;
	return(1);
}

int write_file( fname )
	char	*fname;
{
FILE		*fp;
TextLine	*act;

	fp = fopen( fname, "w" );
	if (fp==NULL)	return(-1);
	act = loaded_text;
	while( act )
	{	if (fputs( act->contents, fp )==EOF)
		{	fprintf(stderr, "write error on file '%s'\n", fname);
			fclose(fp);
			return(-2);
		}
		act = act->next;
	}
	fclose( fp );
	return(0);
}


/********************************************************************************
 *		allocating, freeing, sorting, searching COLORS.			*
 ********************************************************************************/


ColorDef *find_color( name )
	char	*name;
/* searches in the tree of colordefinitions for the named color */
{
ColorDef	*erg, *assoc;
int		i;

	for (i=0;i<color_number;i++)
	{	erg = color[i];
		do
		{
			if (strcase_equal(erg->name, name)==0) {
				erg->pixel = color[i]->pixel;	/* just to be sure that the pixel is set */
				return( erg );
			}
			assoc = erg->associated;
			while( assoc )
			{	if (strcase_equal(assoc->name, name)==0)	return( assoc );
				assoc = assoc->associated;
			}
			erg = erg->brother;
		}
		while (erg);
	}
	return(NULL);
}

void load_color( act )
	ColorDef *act;
/* allocates a pixel for the color, if it is not already allocated. When it's
 * still possible to allocate pixels in the DefaultColormap, this is done and
 * the same color is stored in both maps. If no more cells are available in
 * the DefaultColormap, the program continues working only in its own map.
 */
{
XColor	scr;
long	pixel;

	if (act->pixel==NotAllocated)
	{	if (!only_mine)
		{	if ( (!XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
				NULL, 0, (unsigned long*)&pixel, 1 )) || (pixel>=cells) )
			{
				for (pixel=0;pixel<cells;pixel++)
				{
				    if (my_pixel[pixel])
				    {	XFreeColors( display, DefaultColormapOfScreen(screen), 
				    		(unsigned long*)&pixel, 1, 0 );
				    }
				}

				only_mine=1;
#ifdef CHG_TEXT_WINDOW_COLORMAP
/* when switched on, all windows (not only the textwindow), are displayed
 * in my Colormap, when the DefaultColormap hasn't got any more cells available.
 * Try the option -gran100 and search for the 'gray'-color in the main-window
 * to reach the extremes of the program.
 */
				if (tw)
				{	XSetWindowColormap( display, tw, my_map );
				}
#endif
			}
		}
		if (only_mine)
		{	for (pixel=cells-1;pixel>=0;pixel--)
			{	if (my_pixel[pixel]==0)	break;
			}
	/* the reaction to an overflow in the color-map is hard, but
	 * I can't think of an easy solution for that problem.
	 */		if (pixel<0)
			{	fprintf( stderr, "You did it. The Colormap if full.\n");
				if (CellsOfScreen(screen)>MAX_CELLS)
				{	fprintf( stderr, "Compile the program again with the\n");
					fprintf( stderr, "MAX_CELLS-macro set to an higher value.\n");
				}
				exit(0);
			}
		}
		act -> pixel = pixel;
		scr.pixel = pixel;
		scr.flags = DoRed | DoGreen | DoBlue;
		scr.red   = act->r << 8;
		scr.green = act->g << 8;
		scr.blue  = act->b << 8;
		XStoreColor( display, my_map, &scr );
		if (!only_mine)
			XStoreColor( display, DefaultColormapOfScreen(screen), &scr );
	}
	my_pixel[act->pixel]++;
}

void unload_color( act )
	ColorDef *act;
/* The color is not used anymore. It is possible that the color was loaded
 * more than once and therefor, the cell can't be freed.
 */
{
	if (act->pixel==NotAllocated)	return;

	if ((--my_pixel[act->pixel])==0)
	{	if (!only_mine)
		{	XFreeColors( display, DefaultColormapOfScreen(screen), 
					&act->pixel, 1, 0 );
		}
		act->pixel=NotAllocated;
	}
}

void load_text_colors()
/* to load all colors used in the color-lines of the text-file */
{
int i;

	for (i=0;i<color_lines;i++)
	{	load_color( line[i].color );
		load_color( line[i].help  );
	}
}

void exchange( old, new )
	ColorDef	**old;
	ColorDef	*new;
/* correct exchanging of a loaded color */
{
	if (*old)
	{	unload_color( *old );
	}
	load_color( new );
	*old = new;
}

/*----------------------------------------------------------------------------*/

/*
 * functions to sort the colors
 */

int color_name_sort( p1, p2 )
	ColorString	*p1, *p2;
{
	return(strcmp(p1->name, p2->name));
}

int color_sort( p1, p2 )
	ColorDef	**p1, **p2;
{
char	*s1, *s2;

	if ((*p1)->b!=(*p2)->b)	return(((*p1)->b>(*p2)->b)?1:-1);
	if ((*p1)->g!=(*p2)->g)	return(((*p1)->g>(*p2)->g)?1:-1);
	if ((*p1)->r!=(*p2)->r)	return(((*p1)->r>(*p2)->r)?1:-1);
	s1 = index((*p1)->name, ' ');
	s2 = index((*p2)->name, ' ');
	s1 = s2 = NULL;

	if (s1)
	{	if (s2)	return(strcmp((*p1)->name, (*p2)->name));
		else	return(1);
	}
	else
	{	if (s2)	return(-1);
		else	return(strcmp((*p1)->name, (*p2)->name));
	}
}

int color_sort_r( p1, p2 )
	ColorDef	**p1, **p2;
{
	if ((*p1)->b!=(*p2)->b)	return(((*p1)->b>(*p2)->b)?-1:1);
	if ((*p1)->g!=(*p2)->g)	return(((*p1)->g>(*p2)->g)?-1:1);
	if ((*p1)->r!=(*p2)->r)	return(((*p1)->r>(*p2)->r)?-1:1);
	return(0);
}

void brother_sort( first )
	ColorDef	**first;
{
ColorDef *list[1000];
int	 length;

	length = 0;

	list[length] = *first;
	while(list[length]->brother)
	{	list[length+1] = list[length]->brother;
		length++;
	}

	qsort( (char *)list, length+1, sizeof(ColorDef *), color_sort );

	list[length]->brother = NULL;

	while(length>0)
	{	list[length-1]->brother = list[length];
		length--;
	}
	*first = list[0];
}

void associated_sort( first )
	ColorDef	*first;
{
ColorDef *list[1000];
int	 length;

	length = 0;

	list[length] = first;
	while(list[length]->associated)
	{	list[length+1] = list[length]->associated;
		length++;
	}

	qsort( (char *)&list[1], length, sizeof(ColorDef *), color_sort );

	list[length]->associated = NULL;

	while(length>0)
	{	list[length-1]->associated = list[length];
		length--;
	}
}

/*----------------------------------------------------------------------------*/

/*
 * functions to load the color-file and build the tree with colordefinitions
 */

char *cut_digits( name )
	char	*name;
/* cuts digits from a color-string. returns a pointer to a static string
 * which of course must not be freed. if there where no digits, the original
 * pointer is returned.
 */
{
static char short_name[40];
int i;

	i = strlen(name);
	if ((i>39)||(!isdigit(name[i-1]))||!strncmp(name,"CSO_rgb",7))
		return(name);

	strcpy( short_name, name );
	i--;
	while ((i>0)&&(isdigit(short_name[i])))
	{	short_name[i] = '\0';
		i--;
	}
	return(short_name);
}

void next_name( act )
	ColorDef	*act;
/* collects color-names for the hash-table */
{
	if (act->pixel==Undefined)
	{	fprintf(stderr, "%s not defined.\n", act->name);
		return;
	}
	cname[color_names].name   = act->name;
	cname[color_names].length = strlen(act->name);
	cname[color_names].def    = act;
	color_names++;
}

ColorDef *make_entry( new )
	ColorDef *new;
/* allocates space for the data of a new color */
{
ColorDef	*erg;

	erg = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
	memcpy( (char *)erg, (char *)new, sizeof(ColorDef) );
	erg -> associated = NULL;
	erg -> brother    = NULL;
	erg -> pixel      = NotAllocated;

	return( erg );
}

void new_color( new )
	ColorDef	*new;
/* searches for overlaps in the color-field and stores the new color */
{
char		*search_name;
ColorDef	*act;
ColorDef	*help;
int		i;
int		subname = 0;

	search_name = cut_digits( new->name );
	subname = (search_name!=new->name);

	act = find_color( search_name );

	if (act) {
		if (subname)		/* found and associated entry */
		{	help = act->associated;
			act->associated = make_entry( new );
			act->associated->associated = help;
		}
		else			/* strange: color declared twice ? */
		{	if (act->pixel==Undefined)
			{	memcpy( (char *)act, (char *)new, sizeof(ColorDef)-2*sizeof(ColorDef *) );
				act->pixel = NotAllocated;
			}
			else
			{
				help = act->brother;
				act->brother = make_entry( new );
				act->brother->brother = help;
			}
		}
	}
	else {
		for (i=0;i<color_number;i++)
		{	if ( (new->r==color[i]->r) && (new->g==color[i]->g) && (new->b==color[i]->b) )	break;
		}
		if (i<color_number)
		{	help = color[i]->brother;
			color[i]->brother = make_entry( new );
			color[i]->brother->brother = help;
		}
		else
		{	if (subname)	/* indexed name found before original */
			{	act = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
				memset( (char *)act, (char)-1, sizeof(ColorDef) );
				act->pixel = Undefined;
				act->name  = (char *)malloc((unsigned) strlen(search_name)+1 );
				strcpy( act->name, search_name );
				act->associated = make_entry( new );
				act->brother = NULL;
				color[color_number++] = act;
			}
			else		/* found new color */
			{	color[color_number++] = make_entry( new );
			}
		}
	}
}

load_standard( act )
	ColorDef	*act;
{
XColor		exact_def;

	if (XParseColor( display, DefaultColormapOfScreen(screen), act->name,
		&exact_def ))
	{	act->r = exact_def.red   >> 8;
		act->g = exact_def.green >> 8;
		act->b = exact_def.blue  >> 8;
	}
	new_color( act );
}
		
/*----------------------------------------------------------------------------*/

update_map()
/* sets unused pixels in my_map to the colors (with different intensity)
 * of the DefaultColormap.
 */
{
XColor	qcols[MAX_CELLS];
int	i, j;

	j=0;
	for (i=0;i<cells;i++)
	{	if (my_pixel[i]==0)	qcols[j++].pixel=i;
	}
	XQueryColors( display, DefaultColormapOfScreen(screen), qcols, j );
	for (i=0;i<j;i++)
	{	qcols[i].red   = ((long)qcols[i].red  *darkness)/100;
		qcols[i].green = ((long)qcols[i].green*darkness)/100;
		qcols[i].blue  = ((long)qcols[i].blue *darkness)/100;
		qcols[i].flags = DoRed | DoGreen | DoBlue;
	}
	XStoreColors( display, my_map, qcols, j );
}

create_new_map()
/* get an own colormap */
{
int		i;
XColor		qcols[MAX_CELLS];
unsigned long	pixel[MAX_CELLS];

/* allocate new colormap and copy the darkened colors of the default-map */
	my_map = XCreateColormap( display, mw, 
			XDefaultVisualOfScreen(screen), AllocAll);
	if (my_map==(Colormap)0)
	{	fprintf(stderr, "can't create colormap.\n" );
		exit(0);
	}
	memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );

/* copy the default-map */
	for (i=0;i<cells;i++)	qcols[i].pixel = i;
	XQueryColors( display, DefaultColormapOfScreen(screen), qcols, cells );
	for (i=0;i<cells;i++)
	{	qcols[i].red   = ((long)qcols[i].red  *darkness)/100;
		qcols[i].green = ((long)qcols[i].green*darkness)/100;
		qcols[i].blue  = ((long)qcols[i].blue *darkness)/100;
		qcols[i].flags = DoRed | DoGreen | DoBlue;
	}
	XStoreColors( display, my_map, qcols, cells );

/* try to allocate the color_cells in the default-map */
	if (XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
		NULL, 0, pixel, color_number ))
	{	int	high_value=0;

    /* store the colors into my map and into and into the default-colormap
     * as there are enough cells for both.
     */
		for (i=0;i<color_number;i++)
		{	qcols[i].pixel = pixel[i];
			qcols[i].flags = DoRed | DoGreen | DoBlue;
			qcols[i].red   = color[i]->r << 8;
			qcols[i].green = color[i]->g << 8;
			qcols[i].blue  = color[i]->b << 8;
			color[i]->pixel = pixel[i];
			if (pixel[i]>=cells)
			{	high_value=1;
				break;
			}
			my_pixel[pixel[i]]=1;
		}

		if (high_value)
		{	XFreeColors( display, DefaultColormapOfScreen(screen), 
				pixel, color_number, 0 );
			only_mine = 1;
		}
		else
		{
			XStoreColors( display, DefaultColormapOfScreen(screen), qcols, color_number );
			XStoreColors( display, my_map, qcols, color_number );
			only_mine = 0;
		}
	}
	else	only_mine = 1;

	if (only_mine)
	{
    /* pixels are just used from high to low numbers */
		for (i=0;i<color_number;i++)
		{
			qcols[i].pixel = cells-i-1;
			qcols[i].flags = DoRed | DoGreen | DoBlue;
			qcols[i].red   = color[i]->r << 8;
			qcols[i].green = color[i]->g << 8;
			qcols[i].blue  = color[i]->b << 8;
			color[i]->pixel = cells-i-1;
			my_pixel[cells-i-1]=1;
		}
		XStoreColors( display, my_map, qcols, color_number );

    /* afterwards, all free pixels of the default-map are allocated
     * and set to the values of the new colormap.
     */
		i=0;
		while( XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
			NULL, 0, &pixel[i], 1 ) )
		{	qcols[i].pixel = pixel[i];
			i++;
		}
		XQueryColors( display, my_map, qcols, i );
		XStoreColors( display, DefaultColormapOfScreen(screen), qcols, i );
		XFreeColors( display, DefaultColormapOfScreen(screen), pixel, i, 0 );
		only_mine = 1;
	}

/* the pixels for black, white have to be used from my_map, since
 * the entries of the DefaultColormap are possibly darkened.
 */
	black = find_color( BLACK_STRING )->pixel;
	my_pixel[black]++;
	white = find_color( WHITE_STRING )->pixel;
	my_pixel[white]++;
	grey  = find_color( GREY_STRING )->pixel;
	my_pixel[grey]++;
}

destroy_colormap()
/* not used */
{
unsigned long	pixel[MAX_CELLS];
int	i, j;
ColorDef *assoc, *erg;

	XFreeColormap( display, my_map );
	j=0;
	if (!only_mine)
	{	for (i=0;i<cells;i++)
		{	if (my_pixel[i])	pixel[j++] = i;
		}
		XFreeColors( display, DefaultColormapOfScreen(screen), pixel, j, 0 );
	}
	my_map = 0;
	memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );

	for (i=0;i<color_number;i++)
	{	erg = color[i];
		do
		{	erg->pixel = NotAllocated;
			assoc = erg->associated;
			while( assoc )
			{	assoc->pixel = NotAllocated;
				assoc = assoc->associated;
			}
			erg = erg->brother;
		}
		while (erg);
	}
}


/********************************************************************************
 *			    Textwindow-Functions				*
 ********************************************************************************/


void draw_message( num )
	int	num;
/* draws upper (0) or lower (1) message-entry */
{
int	y;

	y = (num)?(tw_lines+1)*char_height:0;

	XClearArea( display, tw, 0, y, twidth, char_height, False );
	XSetForeground( display, gc, white );
	if (tw_message[num])
	{	XSetFont( display, gc, tinfo->fid );
		XDrawString( display, tw, gc, 
			0, y+tinfo->ascent, 
			tw_message[num], strlen( tw_message[num] ) );
	}
	if (num)	XDrawLine( display, tw, gc, 0, y, twidth, y );
	else		XDrawLine( display, tw, gc, 0, char_height-1, twidth, char_height-1 );
}

void set_message( msg, num )
	char	*msg;
	int	num;
/* sets upper or lower message entry */
{
	if (tw_message[num])		free(tw_message[num]);
	if (msg)
	{	tw_message[num] = (char *)malloc((unsigned) strlen(msg)+1 );
		strcpy( tw_message[num], msg );
	}
	else	tw_message[num]=NULL;

	draw_message( num );
}

void reset_messages()
{
char	mess[20];

	if (act_offset)
	{	sprintf( mess, "*** UP (%d) ***", act_offset);
		set_message( mess, 0 );
	}
	else	set_message( "  click right button here to write file.", 0 );

	if (act_offset+tw_lines<color_lines)
	{	sprintf( mess, "*** DOWN (%d) ***", color_lines-act_offset-tw_lines);
		set_message( mess, 1 );
	}
	else	set_message( (char *)NULL, 1 );
}

void draw_string( i )
	int	i;
/* draws a color-line */
{
int	j;
int	y;
int	p1,p2;
unsigned long	fg_pixel, bg_pixel, help;

	j=i-act_offset;
	if ((tw==(Window)0)||(j<0)||(j>=tw_lines))	return;

	y=(j+1)*char_height;

	fg_pixel = line[i].color->pixel;
	if (fg_pixel==NotAllocated)
	{	fprintf(stderr, "fg_pixel of %s not allocated.\n", line[i].line->contents);
	}
	bg_pixel = line[i].help->pixel;
	if (bg_pixel==NotAllocated)
	{	fprintf(stderr, "bg_pixel of %s not allocated.\n", line[i].line->contents);
	}

	if (line[i].reverse)
	{	help     = fg_pixel;
		fg_pixel = bg_pixel;
		bg_pixel = help;
	}

/* clearing the background */
	XSetForeground(display, gc, bg_pixel);
	XFillRectangle( display, tw, gc, 0, y, twidth, char_height);

	XSetFont( display, gc, tinfo->fid );
	XSetForeground( display, gc, fg_pixel );

	p1 = line[i].pos_in_line;
	p2 = p1 + strlen( line[i].color->name );
	p1 = XTextWidth( tinfo, line[i].line->contents, p1 )+2*char_width;
	p2 = XTextWidth( tinfo, line[i].line->contents, p2 )+2*char_width;

	XDrawString( display, tw, gc, 
		2*char_width, y+tinfo->ascent, 
		line[i].line->contents, strlen(line[i].line->contents)-1 );

	XSetForeground( display, gc, fg_pixel );
	XDrawLine( display, tw, gc, p1, y+char_height-2, p2, y+char_height-2 );	

/* draws the pixmap (at least some planes of it) */
	XSetState( display, gc, (unsigned long)AllPlanes, (unsigned long)0,
				GXxor, fg_pixel^bg_pixel );
	XCopyArea( display, grey_pixmap, tw, gc, 0, 0, char_width, char_height, twidth-3*char_width, y );
	XSetState( display, gc, fg_pixel, bg_pixel,
				GXcopy, (unsigned long)AllPlanes );
	
	if (i==act_line)
	{	XDrawRectangle( display, tw, gc, 0, y, twidth-1, char_height-1);
		XFillRectangle( display, tw, gc, 0, y, 2*char_width, char_height);
		XFillRectangle( display, tw, gc, twidth-2*char_width, y, 2*char_width, char_height);
		XSetForeground( display, gc, bg_pixel );
	}
	else	XSetForeground( display, gc, fg_pixel );

/* drawing indicator 'bg', 'fg', or 'R' */
	if (line[i].reverse)
	{	if (line[i].assoc>=0)
		{	XDrawString( display, tw, gc, 0, y+tinfo->ascent, "bg", 2 );
		}
		else
		{	XSetForeground( display, gc, black );
			XSetBackground( display, gc, white );
			XDrawImageString( display, tw, gc, 0, y+tinfo->ascent, "R", 1 );
		}
	}
	else
	{	if (line[i].assoc>=0)
			XDrawString( display, tw, gc, 0, y+tinfo->ascent, "fg", 2 );
	}
}

void change_color( act_line, new_color )
	int		act_line;
	ColorDef	*new_color;
/* complete change of the color in the given line */
{
int i;

	if (act_line<0)	return;

/* change the string */
	string_exchange( &line[act_line], new_color );

/* allocate the color */
	exchange( &line[act_line].color, new_color );

/* update the window (exchange corresponding color too) */
	draw_string(act_line);
	if (line[act_line].assoc>=0)
	{	exchange( &line[line[act_line].assoc].help, new_color );
		draw_string(line[act_line].assoc);
	}
	if (line[act_line].assoc==-2)
	{ for (i=0;i<color_lines;i++) {
			if (line[i].assoc==-1)
			{	exchange( &line[i].help, new_color );
				draw_string(i);
			}
		}
	}
}

redraw_tw( l1, l2 )
	int	l1, l2;
/* redraws parts of the text-window */
{
int	i;

	if (l1==0)
	{	draw_message( 0 );
		l1++;
	}
	if (l2>tw_lines)
	{	draw_message( 1 );
		l2=tw_lines;
	}
	for (i=l1;i<=l2;i++)	draw_string( act_offset+i-1 );
}

/*----------------------------------------------------------------------------*/

void show_string( row, text )
	int		row;
	TextLine	*text;
{
	if (text)
	{	XSetForeground( display, gc, white );
		XFillRectangle( display, tw, gc, 0, row*char_height, twidth, char_height );
		XSetForeground( display, gc, black );
		XDrawString( display, tw, gc, 
			2*char_width, row*char_height+tinfo->ascent, 
			text->contents, strlen(text->contents) );
	}
	else
	{	XSetForeground( display, gc, black );
		XFillRectangle( display, tw, gc, 0, row*char_height, twidth, char_height );
	}
}

void show_text( i )
	int	i;
/* shows the part of the text, where line i occurred. The old contents of the
 * text-window is stored in a pixmap if possible.
 */
{
TextLine	*upper,*lower;
int		upper_i,lower_i;
XEvent		event;
Pixmap		back;

	back = XCreatePixmap( display, tw, twidth, (tw_lines+2)*char_height, DefaultDepthOfScreen(screen) );
	if (back)
	{	XCopyArea( display, tw, back, gc, 
			0, 0, twidth, (tw_lines+2)*char_height, 
			0, 0 );
	}
	
	XGrabPointer(display, tw, False, 
		ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, 
		tw, text_cursor, CurrentTime );
	XSetFont( display, gc, tinfo->fid );

	upper   = line[i].line;
	upper_i = i-act_offset+1;
	XSetForeground( display, gc, grey );
	XFillRectangle( display, tw, gc, 0, upper_i*char_height, twidth, char_height );
	XSetForeground( display, gc, black );
	XDrawString( display, tw, gc, 
		2*char_width, upper_i*char_height+tinfo->ascent, 
		upper->contents, strlen(upper->contents) );

	lower = upper;
	upper = upper;
	lower_i = upper_i + 1;
	upper_i--;

	while( ( upper_i>=0 )||(lower_i<=tw_lines+1) )
	{	if ( upper_i>=0 )
		{	if (upper)	upper=upper->previous;
			show_string( upper_i--, upper );
		}
		if (lower_i<=tw_lines+1)
		{	if (lower)	lower=lower->next;
			show_string( lower_i++, lower );
		}
	}

	XWindowEvent( display, tw, ButtonPressMask|ButtonReleaseMask, &event );

	XUngrabPointer( display, CurrentTime );
	if (back)
	{	XCopyArea( display, back, tw, gc, 
			0, 0, twidth, (tw_lines+2)*char_height, 
			0, 0 );
		XFreePixmap( display, back );
	}
	else	redraw_tw( 0, tw_lines+1 );
}

/*----------------------------------------------------------------------------*/

void write_quest( num )
	int	num;
/* waits for a confirmation before the file is written with backup. */
{
XEvent	event;

	set_message( "  confirm writing with right button !", num );
	XBell( display, 10 );

	XGrabPointer(display, tw, False, 
		ButtonPressMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, quest_cursor, CurrentTime );
	XWindowEvent( display, tw, ButtonPressMask|LeaveWindowMask, &event );

	if ((event.xany.type==ButtonPress)&&(event.xbutton.button==Button3))
	{	char	back_name[MAXPATHLEN];

		strcpy( back_name, file_name );
		strcat( back_name, "~" );

		if (rename( file_name, back_name ))
		{	set_message("  can't create backup. writing aborted.", num);
		}
		else
		{	if (write_file( file_name ))
				set_message("  writing failed.", num);
			else	set_message("  file written with backup.", num);
		}
	}
	else set_message("  writing aborted.", num);

	XUngrabPointer( display, CurrentTime );
}

/*----------------------------------------------------------------------------*/

void new_assoc( act )
	int	act;
/* the function waits, until the button is released or the mouse is moved
 * into an associated line. If both lines were already connected, they get
 * disconnected. If no line was connected, the first line will get the
 * foreground and the second line the background of the association.
 */
{
XEvent	event;
int	new;

	if (line[act].assoc>=0)
	{	set_message( "  move to associated line to disconnect.", 0 );
	}
	else	set_message( "  move to background to connect.", 0 );

	XGrabPointer(display, tw, False, 
		ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, tw, updown_cursor, CurrentTime );

	new = act;
	do
	{	XWindowEvent( display, tw, ButtonReleaseMask|PointerMotionMask, &event );
		if (event.xany.type==MotionNotify)
		{	new = (event.xmotion.y/char_height)+act_offset-1;
			if (new!=act)	break;
		}
	}
	while( event.xany.type!=ButtonRelease );

	if (new==act)
	{	if (line[act].assoc<0)
		{	line[act].reverse^=1;
		}
		else
		{	ColorDef	*help;

			help = line[act].color;
			change_color( act, line[line[act].assoc].color );
			change_color( line[act].assoc, help );
		}
		reset_messages();
	}
	else
	{	if (line[act].assoc<0)
		{	if (line[new].assoc<0)
			{	set_message( "  new association set.", 0 );
				XBell( display, 5 );

				line[act].assoc   = new;
				exchange( &line[act].help, line[new].color );
				line[act].reverse = 0;

				line[new].assoc   = act;
				exchange( &line[new].help, line[act].color );
				line[new].reverse = 1;

				draw_string( new );
				draw_string( act );
			}
			else
			{	set_message( "  line already connected.", 0 );
				XBell( display, 10 );
			}
		}
		else
		{	if (line[act].assoc==new)
			{	set_message( "  disconnected.", 0 );
				XBell( display, 5 );
				line[act].assoc = -1;
				line[new].assoc = -1;
				draw_string( new );
				draw_string( act );
			}
			else
			{	set_message( "  lines not associated.", 0 );
				XBell( display, 10 );
			}
		}
	}

	while (event.xany.type!=ButtonRelease)
	{	XWindowEvent( display, tw, ButtonReleaseMask, &event );
	}
	XUngrabPointer( display, CurrentTime );
}

/*----------------------------------------------------------------------------*/

void tw_event( event )
	XEvent	*event;
/* event-execution for the text-window */
{
    switch( event->xany.type )
    {
	case ConfigureNotify:
	{	XEvent	help;
		int	tw_new;
	
		tw_new = (event->xconfigure.height/char_height)-2;
		if ((twidth==event->xconfigure.width)&&(tw_lines==tw_new))	break;

		twidth   = event->xconfigure.width;
		tw_lines = tw_new;

		if (tw_lines>color_lines)	tw_lines=color_lines;
		if (act_offset+tw_lines>color_lines)
			act_offset = color_lines-tw_lines;

		redraw_tw( 0, tw_lines+1 );
		XSync(display, 0);
		while( XCheckWindowEvent( display, tw, ExposureMask, &help ) );

		break;
	}

	case KeyPress:
	{	char	sign;
		KeySym	keysym;

	   	XLookupString(&event->xkey, &sign, 1, &keysym, NULL);
		if (sign=='q')	exit(0);
		break;
	}

	case Expose:
	{	XEvent	help;
		int	first, first2;
		int	last, last2;

		first = event->xexpose.y/char_height;
		last  = (event->xexpose.y + event->xexpose.height)/char_height+1;

		while( XCheckWindowEvent( display, tw, ExposureMask, &help ) )
		{	first2 = help.xexpose.y/char_height;
			last2  = (help.xexpose.y + help.xexpose.height)/char_height+1;

			if (first2 < first)	first = first2;
			if (last2  > last)	last  = last2;
		}
		redraw_tw( first, last );
		break;
	}

	case ButtonPress:
	{	int	i;
		int	old_act;
		int	offset_delta;

		i= (event->xbutton.y / char_height)-1;

	/* has the header or footer of the textwindow been selected ? */
		if (i<0)
		{	if (event->xbutton.button==Button3)
			{	write_quest(0);
				return;
			}
			else if (act_offset)
			{	offset_delta=(event->xbutton.button==Button1)?1:10;
				if (act_offset-offset_delta<0)
					offset_delta = act_offset;
				act_offset -= offset_delta;
				XCopyArea( display, tw, tw, gc,
					0, char_height, twidth, (tw_lines-offset_delta)*char_height,
					0, (offset_delta+1)*char_height );
				redraw_tw( 1, offset_delta+1 );
			}
			else	XBell(display, 10);
			break;
		}
		if (i>=tw_lines)
		{	if (event->xbutton.button==Button3)
			{	write_quest(1);
				return;
			}
			else if (act_offset+tw_lines<color_lines)
			{	offset_delta=(event->xbutton.button==Button1)?1:10;
				if (act_offset+offset_delta>color_lines-tw_lines)
					offset_delta = color_lines-act_offset-tw_lines;
				act_offset += offset_delta;
				XCopyArea( display, tw, tw, gc,
					0, (offset_delta+1)*char_height,
					twidth, (tw_lines-offset_delta)*char_height,
					0, char_height );
				redraw_tw( tw_lines-offset_delta+1, tw_lines );
			}
			else	XBell(display, 10);
			break;
		}
		i+=act_offset;

	/* action on a textline depending on the button */
		switch(event->xbutton.button)
		{
		case Button2:
			old_act  = act_line;
			act_line = -1;
			draw_string( old_act );
			new_assoc( i );
			act_line=i;
			draw_string( act_line );
			return;

		case Button1:
			old_act = act_line;
			act_line = i;
			draw_string( old_act );
			draw_string( act_line );
			break;

		case Button3:
			old_act = act_line;
			act_line = i;
			draw_string( old_act );
			show_text( act_line );
			draw_string( act_line );
			break;
		}
	} /* end case ButtonPress */
    } /* end switch(type) */
    reset_messages();
}

/*----------------------------------------------------------------------------*/

Window create_textwindow( fname )
	char	*fname;
{
Window			tw;
XSizeHints		hints;
XWMHints		normal_hints;
XClassHint		class_hints;

static char *iname = "TextView";
char	wname[MAXPATHLEN+10];
char	*name_ptr;

/* parsing the geometry */ 
	hints.flags = PSize | PMaxSize | PMinSize | PResizeInc;

	if (color_lines<4)	hints.min_height = (color_lines+2) * (char_height);
	else			hints.min_height = 7 * (char_height);
	hints.min_width = 20 * char_width;

	if (color_lines>50)	tw_lines = 25;
	else			tw_lines = color_lines;
	hints.width = longest_colored+ 6 * char_width;
	hints.height= (tw_lines+2) * (char_height);
	act_offset = 0;

	hints.max_height = (color_lines+2) * (char_height);
	hints.max_width = 2*(longest_colored);

	hints.width_inc  = char_width;
	hints.height_inc = char_height;

	twidth = hints.width;

/* names */
	name_ptr = rindex( fname, '/' );
	if (name_ptr)	fname = name_ptr+1;

	sprintf( wname, "TextView '%s'", fname );
	name_ptr = wname;

	tw = XCreateSimpleWindow( display, RootWindowOfScreen(screen), 
		0, 0, hints.width, hints.height, 3, grey, black );

/* class-hints */
	class_hints.res_name = "xcol";
	class_hints.res_class= "XCol";

/* normal-hint */
	normal_hints.flags = StateHint | WindowGroupHint;
	
	normal_hints.initial_state = NormalState;
	normal_hints.window_group  = mw;

#ifdef XTextProperty
{	
XTextProperty		window_name, icon_name;

	XStringListToTextProperty( &name_ptr, 1, &window_name );
	XStringListToTextProperty( &iname, 1, &icon_name );
	
	XSetWMProperties( display, tw, &window_name, &icon_name, (char **)0, 0, 
				&hints, &normal_hints, &class_hints );

	XFree( (char *)window_name.value );
	XFree( (char *)icon_name.value );
}
#else
	XSetStandardProperties( display, tw, name_ptr, iname, None, (char **)0, 0, &hints );
	XSetClassHint( display, tw, &class_hints );
#endif

	XSelectInput( display, tw, 
		ExposureMask | ButtonPressMask | StructureNotifyMask |
		KeyPressMask | EnterWindowMask | LeaveWindowMask );
	XDefineCursor( display, tw, tw_cursor );
	XMapRaised( display, tw );
	return( tw );
}


/********************************************************************************
 *			    Subwindow-Functions					*
 ********************************************************************************/


void destroy_subwindow( i )
	int	i;
/* destroys the tiny subwindow and its associated colors */
{
ColorDef	*act;

	act  = color[i];
	while( act->associated )
	{	act = act->associated;
		unload_color( act );
	}
	XDestroyWindow( display, subw );
}

void create_subwindow( i )
	int	i;
/* creates, maps and draws a tiny information-window for the given color */
{
XSetWindowAttributes    attrib;
int	x, y;
int	subs;
int	j;
ColorDef	*shades[MAX_COLS];
ColorDef	*act;
int	bord=6;

/* what associated color should be shown ? */
	act = color[i];
	subs = 0;
	shades[subs++] = act;
	while( act->associated )
	{	act = act->associated;
		shades[subs++]=act;
	}
	if (subs>gran+1)
	{	for (j=0;j<(gran);j++)
		{	shades[j+1]= shades[1+(j*(subs-2))/(gran-1)];
		}
		subs=gran+1;
	}
	for (j=0;j<subs;j++)		load_color( shades[j] );
	
/* compute size */
	sdx = XTextWidth( finfo, color[i]->name, strlen(color[i]->name) )+4;
	sdy = finfo->ascent + finfo->descent+2;
	if (subs>1)
	{	int	palette_width=8;

		sdy += 14;
		if (sdx<(subs*palette_width))
		{	do
			{	sdx=subs*palette_width;
				palette_width--;
			}
			while( (sdx+2*bord>dx)&&(palette_width>3) );
		}
		subcols = subs;
	}
	else
	{	subcols = subs = 0;
	}

/* compute position */
	if (color[i]->x < dx/2)		x = color[i]->x + BO;
	else				x = color[i]->x -BO -(2*bord) -sdx;
	if (x+sdx+(2*bord)>dx)		x = dx - sdx - (2*bord);
	if (x<0)			x=0;

	if (color[i]->y < dy/2)		y = color[i]->y + BO;
	else				y = color[i]->y -BO -(2*bord) -sdy;

/* create, map and draw */
	subw = XCreateSimpleWindow( display, mw, x, y, sdx, sdy, bord, color[i]->pixel, black );
	attrib.save_under = True;
	XChangeWindowAttributes( display, subw, CWSaveUnder, &attrib );
	XMapRaised( display, subw );

	XSetFont( display, gc, finfo->fid );
	XSetForeground( display, gc, white );
	XSetBackground( display, gc, black );
	XDrawImageString( display, subw, gc, 
				(sdx-XTextWidth( finfo, color[i]->name, strlen(color[i]->name)))>>1, 
				finfo->ascent, color[i]->name, strlen( color[i]->name ) );
	if (subs)
	{	for (j=0;j<subs;j++)
		{
			XSetForeground( display, gc, shades[j]->pixel );
			XFillRectangle( display, subw, gc, 2+j*(sdx-2)/subs, sdy-12, (j+1)*(sdx-2)/subs-(2+j*(sdx-2)/subs), 10);
		}
	}
}

/*----------------------------------------------------------------------------*/

/* LittleBox draws 2 rectangles around a color-field of the subwindow */
#define	LittleBox(col)							\
	XDrawRectangle( display, subw, gc, 				\
		1+col*(sdx-2)/subcols, sdy-13, 				\
		(col+1)*(sdx-2)/subcols-(2+col*(sdx-2)/subcols)+1, 11);	\
	XDrawRectangle( display, subw, gc, 				\
		1+col*(sdx-2)/subcols-1, sdy-13-1, 			\
		(col+1)*(sdx-2)/subcols-(2+col*(sdx-2)/subcols)+1+2, 11+2)


void sub_select( line_index, i, help_color )
	int	line_index, i, help_color;
/* select a sub-color */
{
ColorDef *shades[MAX_COLS];
ColorDef *act;
int	subs, j;
XEvent	event;
int	col_index;	/* current index to the shades-field */
int	old_col_index;	/* last index to the shades-field */

/* collect shades (shades[0] is used for the old value of the color) */
	if (help_color)		shades[0] = line[line_index].help;
	else			shades[0] = line[line_index].color;

	act = color[i];
	subs = 1;
	shades[subs++] = act;
	while( act->associated )
	{	act = act->associated;
		shades[subs++]=act;
	}

	if (subs>gran+1)
	{	for (j=0;j<(gran);j++)
		{	shades[j+2]= shades[2+(j*(subs-3))/(gran-1)];
		}
	}

/* first exchange of the color */
	col_index = 0;
	if (help_color)
	{	exchange( &line[line_index].help, shades[col_index+1] );
		draw_string( line_index );
	}
	else	change_color( line_index, shades[col_index+1] );

/* if there are no associated colors, the selection is done */
	if (subs<=2)	return;

	col_index=0;
	old_col_index=0;
	XSetForeground( display, gc, white );
	LittleBox( col_index );

/* warp the pointer to the main color of the subwindow */
	XWarpPointer( display, None, subw, 0, 0,  0, 0, ((sdx/subcols)>>1)+2, sdy-7 );
	XGrabPointer(display, subw, False, 
		ButtonPressMask | ButtonReleaseMask | PointerMotionMask, 
		GrabModeAsync, GrabModeAsync, 
		subw, subsel_cursor, CurrentTime );

	do
	{	XWindowEvent( display, subw, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &event );
		if (event.xany.type!=ButtonRelease)
		{
			if (event.xany.type==MotionNotify)
			{	while(XCheckMaskEvent(display, PointerMotionMask, &event));

				col_index = (event.xmotion.x-1)*subcols/(sdx-2);
				if (col_index<0)	col_index=0;
				if (col_index>=subcols)	col_index=subcols-1;

				if ((event.xmotion.y<sdy-13)||(event.xmotion.y>sdy-2))
				{	col_index = -1;
				}
			}
			else		col_index = -1;	/* another ButtonPress == abort */

			if (old_col_index!=col_index)
			{	if (old_col_index>=0)
				{	XSetForeground( display, gc, black );
					LittleBox( old_col_index );
				}
				if (col_index>=0)
				{	XSetForeground( display, gc, white );
					LittleBox( col_index );
				}
				old_col_index = col_index;
				if (help_color)
				{	exchange( &line[line_index].help, shades[col_index+1] );
					draw_string( line_index );
				}
				else	change_color( line_index, shades[col_index+1] );
			}
		}
	}
	while( event.xany.type==MotionNotify );

	XUngrabPointer(display, CurrentTime);
	XSetForeground( display, gc, black );
	LittleBox( old_col_index );
/* warp pointer back to its former position */
	XWarpPointer( display, None, mw, 0, 0, 0, 0, shades[1]->x, shades[1]->y );
	XSync(display, 1);
}


/********************************************************************************
 *			    main-window-functions				*
 ********************************************************************************/


int act_color( x, y )
	int	x, y;
/* queries the next color in range of the mouse-pointer */
{
int i;
int min_dist;
int min_i = 0;
int dx1, dy1;

	min_dist = dy*dy+dx*dx;

	for (i=0;i<color_number;i++)
	{	dx1 = abs(color[i]->x-x);
		dy1 = abs(color[i]->y-y);

		if (dx1*dx1+dy1*dy1<min_dist)
		{	min_dist = dx1*dx1+dy1*dy1;
			min_i = i;
		}
	}
	if (min_dist<(BO)*(BO))
		return(min_i);
	else
		return(-1);
}

/*----------------------------------------------------------------------------*/
	
#define	XPos(r, g, b)	( (BO>>1)+2+					\
			  ( (reverse)	? (85+(255-r)-((255-b)/3))	\
			  		: (85+r-((b)/3))		\
			  ) * (dx-BO-4)/341				\
			)
#define	YPos(r, g, b)	( (BO>>1)+2+					\
			  ( (reverse)	? (g+((255-b)>>1))		\
			  		: ((255-g)+(b>>1))		\
			  ) * (dy-BO-4)/384				\
			)

void redraw_window()
/* redraws the cube and the color-boxes in the main window */
{
int i, j, op;
int ex[8], ey[8];
int s_dummy;
unsigned int u_dummy;
Window	root;

	XGetGeometry( display, mw, &root, &s_dummy, &s_dummy, &dx, &dy, &u_dummy, &u_dummy );
	if (BO_def)
		BO = BO_def;
	else
	{	BO = (dx/50);
		if ((dy/50)>BO)	BO=(dy/50);
	}
	XClearWindow( display, mw );

/* draw the cube */
	XSetForeground( display, gc, white );
	for (i=0;i<8;i++)
	{	ex[i] = XPos( ((i&1)?255:0), ((i&2)?255:0), ((i&4)?255:0) );
		ey[i] = YPos( ((i&1)?255:0), ((i&2)?255:0), ((i&4)?255:0) );
	}
	for (i=0;i<8;i++)
	{	for (j=0;j<3;j++)
		{	op = i^(1<<j);
			if (op<i)
				XDrawLine(display, mw, gc, ex[i], ey[i], ex[op], ey[op]);
		}
	}

/* draw the boxes */
	for (i=0;i<color_number;i++)
	{
		color[i]->x = XPos(color[i]->r, color[i]->g, color[i]->b);
		color[i]->y = YPos(color[i]->r, color[i]->g, color[i]->b);

		XSetForeground( display, gc, color[i]->pixel );
		XFillRectangle( display, mw, gc, 
			color[i]->x-(BO>>1), color[i]->y-(BO>>1), BO, BO);
	}
	XFlush(display);
}

/*----------------------------------------------------------------------------*/

mw_event( event )
	XEvent	*event;
{
static int new_i;
static int old_i= -1;

    switch( event->xany.type )
    {
    case Expose:
    		while(XCheckWindowEvent( display, mw, ExposureMask, event ));

    		if (event->xexpose.count==0)	redraw_window();
    		break;

    case MotionNotify:
    		while( XCheckWindowEvent( display, mw, PointerMotionMask, event ) );
		new_i = act_color( event->xmotion.x, event->xmotion.y );
		if ((old_i!=new_i)&&(old_i>=0))
		{	destroy_subwindow(old_i);
			old_i = -1;
		}
		if (old_i!=new_i)
		{	create_subwindow(new_i);
			old_i = new_i;
		}
    		break;

    case EnterNotify:
    	update_map();
    	break;

    case LeaveNotify:
    	if (old_i>=0)
    	{	destroy_subwindow(old_i);
    		old_i = -1;
    	}
    	break;

    case ButtonPress:
        switch (event->xbutton.button)
    	{
    	    case Button1:
    	    {	if ((tw)&&(old_i>=0))
		{	sub_select( act_line, old_i, 0 );
		}
		else
		{	if (old_i>=0)
			{	sub_select( 0, old_i, 0 );
				XStoreBytes( display, line[0].color->name, strlen(line[0].color->name) );
				XBell(display, 10);
			}
		}
		break;	/* end switch(button) */
	    }

	    case Button2:
	    {	if ((tw)&&(act_line>=0)&&(old_i>=0))
		{	if (line[act_line].assoc<0)
				sub_select( act_line, old_i, 1 );
			else	sub_select( line[act_line].assoc, old_i, 0 );
		}
		break;	/* end switch(button) */
	    }

	    case Button3:
	    {	ColorDef	*act;
		char		*short_name;
		char		*name;
		char		name_copy[30];
		int		name_length;

		name = short_name = NULL;

		if ((tw)&&(act_line>=0))
		{	short_name = cut_digits( line[act_line].color->name );
		}
		else
		{	if (tw==(Window)0)
			{	name = XFetchBytes( display, &name_length );
				if (name_length<28)
				{	strncpy( name_copy, name, name_length );
					name_copy[ name_length ] = '\0';
					short_name = cut_digits( name );
				}
				XFree( name );
			}
		}
		if (short_name)
		{	act = find_color( short_name );
			if (act)
			XWarpPointer( display, None, mw, 0, 0,  0, 0, 
				XPos( act->r, act->g, act->b ), 	YPos( act->r, act->g, act->b ) );
		}
		if (name)	XFree(name);

		break;	/* end switch(button) */
	    }
 
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions