1 
2 #include <X11/Xlib.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 
6 #ifndef __color_mapper_h
7 #	include "color_mapper.H"
8 #endif
9 
ColorMapper(Display * dpy_in)10 ColorMapper::ColorMapper(Display *dpy_in)
11 : dpy(dpy_in)
12 {
13 Screen	*screen = DefaultScreenOfDisplay(dpy);
14 
15 	mymap=DefaultColormapOfScreen(screen);
16 	cells=0;
17 	colors=0;
18 	if (DefaultVisualOfScreen(screen)->c_class!=PseudoColor)		return;
19 
20 	cells=CellsOfScreen(screen);
21 	colors      = new XColor[cells];
22 	setup_usage();
23 }
24 
~ColorMapper()25 ColorMapper::~ColorMapper() {
26 	free_usage();
27 	if (colors)			delete [] colors;
28 }
29 
free_usage()30 void ColorMapper::free_usage() {
31 int i;
32 
33 	for (i=0;i<cells;i++) {
34 		if (colors[i].flags) {
35    		XFreeColors(dpy,mymap,&colors[i].pixel,1,0L);
36    	}
37 	}
38 }
39 
setup_usage()40 void ColorMapper::setup_usage() {
41 int i;
42 unsigned long	*help;
43 
44 	for (i=0;i<cells;i++)	colors[i].pixel = i;
45 	XQueryColors(dpy,mymap,colors,cells);
46 	for (i=0;i<cells;i++)	colors[i].flags = DoRed | DoGreen | DoBlue;
47 
48 	help = new unsigned long[cells];
49 /*
50  * allocate unused cells of the colormap for read/write
51  */
52    i = 0;
53    while(XAllocColorCells( dpy, mymap, False, 0L, 0, &help[i], 1 )) {
54    	colors[help[i]].flags = 0;		// mark unusable for shared color
55    	i++;
56    }
57 
58 /*
59  * free the pixels again
60  */
61    XFreeColors(dpy,mymap,help,i,0L);
62    delete [] help;
63    XSync( dpy, 0 );
64 
65    for (i=0;i<cells;i++) {
66    	if (colors[i].flags) {		// still not invalidated
67    	// all shareable colors are again allocated !!
68    		if (XAllocColor(dpy,mymap,&colors[i])) {
69    			if ((unsigned)i!=colors[i].pixel) {
70    				XFreeColors(dpy,mymap,&colors[i].pixel,1,0L);
71    				colors[i].flags=0;		// different pixel -> not usefull
72    			}
73    		}
74    		else {
75    				colors[i].flags=0;		// not allocatable -> not usefull
76    		}
77    	}
78    }
79    return;
80 }
81 
alloc_color(XColor * def)82 unsigned long ColorMapper::alloc_color(XColor *def) {
83 int	i;
84 long	min_dist=0;
85 int	min_i;
86 
87 	if (!colors) {
88 		def->flags=DoRed | DoGreen | DoBlue;
89 		if (!XAllocColor(dpy,mymap,def)) {
90 			fprintf( stderr, "\n*** failed to allocated color on '%s'\n\n", DisplayString(dpy) );
91 			exit(0);
92 		}
93 		return def->pixel;
94 	}
95 
96 	min_i=-1;
97 	for (i=0;i<cells;i++) {
98 		if (colors[i].flags) {
99 			long rd = ((long)colors[i].red   - (long)def->red)/4;
100 			long gd = ((long)colors[i].green - (long)def->green)/4;
101 			long bd = ((long)colors[i].blue  - (long)def->blue)/4;
102 			long dist=rd*rd+gd*gd+bd*bd;
103 
104 			if (min_i<0 || dist<min_dist) {
105 				min_dist = dist;
106 				min_i    = i;
107 			}
108 		}
109 	}
110 
111 // reuse already allocated color, when possible
112 	if (min_i>=0 && min_dist<15000) {
113 		return colors[min_i].pixel;
114 	}
115 
116 // allocate additional entry for that pixel
117 	def->flags=DoRed | DoGreen | DoBlue;
118 	if (XAllocColor(dpy,mymap,def)) {
119 		colors[def->pixel] = *def;
120 		return def->pixel;
121 	}
122 
123 // allocate the closest entry
124 	if (min_i>=0) {
125 		return colors[min_i].pixel;
126 	}
127 
128 // everything else failed ...
129 	fprintf( stderr, "can't handle colormap overflow ...\n" );
130 	exit(0);
131 	return 0;	// to eliminate warning
132 }
133 
alloc_named_color(const char * name)134 unsigned long ColorMapper::alloc_named_color( const char *name ) {
135 XColor   def;
136 	if (!XLookupColor(dpy,mymap,name,&def,&def )) {
137 		fprintf( stderr, "\n*** failed to query color '%s'\n\n", name );
138 		exit(0);
139 	}
140 	def.flags = DoRed | DoGreen | DoBlue;
141 	return alloc_color(&def);
142 }
143