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;
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 	min_dist=0;
98 	for (i=0;i<cells;i++) {
99 		if (colors[i].flags) {
100 			long rd = ((long)colors[i].red   - (long)def->red)/4;
101 			long gd = ((long)colors[i].green - (long)def->green)/4;
102 			long bd = ((long)colors[i].blue  - (long)def->blue)/4;
103 			long dist=rd*rd+gd*gd+bd*bd;
104 
105 			if (min_i<0 || dist<min_dist) {
106 				min_dist = dist;
107 				min_i    = i;
108 			}
109 		}
110 	}
111 
112 // reuse already allocated color, when possible
113 	if (min_i>=0 && min_dist<10000) {
114 		return colors[min_i].pixel;
115 	}
116 
117 // allocate additional entry for that pixel
118 	def->flags=DoRed | DoGreen | DoBlue;
119 	if (XAllocColor(dpy,mymap,def)) {
120 		colors[def->pixel] = *def;
121 		return def->pixel;
122 	}
123 
124 // allocate the closest entry
125 	if (min_i>=0) {
126 		return colors[min_i].pixel;
127 	}
128 
129 // everything else failed ...
130 	fprintf( stderr, "can't handle colormap overflow ...\n" );
131 	exit(0);
132 	return 0;
133 }
134 
alloc_named_color(const char * name)135 unsigned long ColorMapper::alloc_named_color( const char *name ) {
136 XColor   def;
137 	if (!XLookupColor(dpy,mymap,name,&def,&def )) {
138 		fprintf( stderr, "\n*** failed to query color '%s'\n\n", name );
139 		exit(0);
140 	}
141 	def.flags = DoRed | DoGreen | DoBlue;
142 	return alloc_color(&def);
143 }
144 
145 // ============================================================================
146 
Port(Display * dpy_in)147 Port::Port(Display *dpy_in) {
148 	dpy = dpy_in;
149 	mapper = new ColorMapper(dpy);
150 }
151 
~Port()152 Port::~Port() {
153 	delete mapper;
154 }
155