1 /*
2  *  This file is part of the XForms library package.
3  *
4  *  XForms is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU Lesser General Public License as
6  *  published by the Free Software Foundation; either version 2.1, or
7  *  (at your option) any later version.
8  *
9  *  XForms is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with XForms.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 /**
20  * \file flcolor.c
21  *
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  * Colormap management.
27  *
28  *  XForm will by default use the visual that has the most depth
29  *  and share colormap if possible. The default behavior can be
30  *  overridden by resource class Visual and Depth.
31  *
32  *  Pixel is addressed via two indirections. First all colors
33  *  are addressed using the FL defined symbolic names, FL_RED, etc
34  *  which are then translated via a secondary lookup table to
35  *  get the true pixel values as known by the server.
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 
42 #include "include/forms.h"
43 #include "flinternal.h"
44 
45 /******************* Local variables ************************/
46 
47 static unsigned long *lut;
48 static unsigned long max_server_cols;   /* max cols in current visual       */
49 static long cols_in_default_visual;
50 static long predefined_cols;    /* min(max_server_col, built_in_col) */
51 static int allow_leakage;
52 static FL_COLOR lastmapped;     /* so fli_textcolor can refresh its cache */
53 
54 
55 static void fli_free_newpixel( unsigned long );
56 static FL_COLOR rgb2pixel( unsigned int, unsigned int, unsigned int );
57 
58 /* this needs to be changed to a lookup table */
59 
60 #ifndef FL_RGB2GRAY
61 #define FL_RGB2GRAY( r, g, b )  \
62     ( ( 78 * ( r ) + 150 * ( g ) + 28 * ( b ) ) >> 8 )
63 #endif
64 #define NV( a )  #a,a
65 
66 
67 /* Default colormap entry for FORMS, subject to gamma corrections.
68  *
69  * The map entries are listed in the order of importance based
70  * on which color we need most in case the Xserver does not have
71  * enough depths to get them all. */
72 
73 static FLI_IMAP fli_imap[ FL_MAX_COLS ] =
74 {
75 	{ NV( FL_BLACK                ),   0,   0,   0, 0, 0 },
76 	{ NV( FL_WHITE                ), 255, 255, 255, 0, 0 },
77 	{ NV( FL_COL1                 ), 173, 173, 173, 0, 0 },
78 	{ NV( FL_BOTTOM_BCOL          ),  89,  89,  89, 0, 0 },
79 	{ NV( FL_RIGHT_BCOL           ),  41,  41,  41, 0, 0 },
80 	{ NV( FL_MCOL                 ), 191, 191, 191, 0, 0 },
81 	{ NV( FL_LEFT_BCOL            ), 222, 222, 222, 0, 0 },
82 	{ NV( FL_SLATEBLUE            ), 113, 113, 198, 0, 0 },
83 	{ NV( FL_INDIANRED            ), 198, 113, 113, 0, 0 },
84 	{ NV( FL_RED                  ), 255,   0,   0, 0, 0 },
85 	{ NV( FL_BLUE                 ),   0,   0, 255, 0, 0 },
86 	{ NV( FL_GREEN                ),   0, 255,   0, 0, 0 },
87 	{ NV( FL_YELLOW               ), 255, 255,   0, 0, 0 },
88 	{ NV( FL_MAGENTA              ), 255,   0, 255, 0, 0 },
89 	{ NV( FL_CYAN                 ),   0, 255, 255, 0, 0 },
90 	{ NV( FL_TOMATO               ), 255,  99,  71, 0, 0 },
91 	{ NV( FL_INACTIVE             ), 110, 110, 110, 0, 0 },
92 	{ NV( FL_TOP_BCOL             ), 204, 204, 204, 0, 0 },
93 	{ NV( FL_PALEGREEN            ), 113, 198, 113, 0, 0 },
94 	{ NV( FL_DARKGOLD             ), 205, 149,  10, 0, 0 },
95 	{ NV( FL_ORCHID               ), 205, 105, 201, 0, 0 },
96 	{ NV( FL_DARKCYAN             ),  40, 170, 175, 0, 0 },
97 	{ NV( FL_DARKTOMATO           ), 139,  54,  38, 0, 0 },
98 	{ NV( FL_WHEAT                ), 255, 231, 155, 0, 0 },
99 	{ NV( FL_DARKORANGE           ), 255, 128,   0, 0, 0 },
100 	{ NV( FL_DEEPPINK             ), 255,   0, 128, 0, 0 },
101 	{ NV( FL_CHARTREUSE           ), 128, 255,   0, 0, 0 },
102 	{ NV( FL_DARKVIOLET           ), 128,   0, 255, 0, 0 },
103 	{ NV( FL_SPRINGGREEN          ),   0, 255, 128, 0, 0 },
104 	{ NV( FL_DODGERBLUE           ),   0, 128, 255, 0, 0 },
105 	{ NV( FL_DOGERBLUE            ),   0, 128, 255, 0, 0 },
106 	{ NV( FL_LIGHTER_COL1         ), 204, 204, 204, 0, 0 },
107 	{ NV( FL_DARKER_COL1          ), 161, 161, 161, 0, 0 },
108 	{ NV( FL_ALICEBLUE            ), 240, 248, 255, 0, 0 },
109 	{ NV( FL_ANTIQUEWHITE         ), 250, 235, 215, 0, 0 },
110 	{ NV( FL_AQUA                 ),   0, 255, 255, 0, 0 },
111 	{ NV( FL_AQUAMARINE           ), 127, 255, 212, 0, 0 },
112 	{ NV( FL_AZURE                ), 240, 255, 255, 0, 0 },
113 	{ NV( FL_BEIGE                ), 245, 245, 220, 0, 0 },
114 	{ NV( FL_BISQUE               ), 255, 228, 196, 0, 0 },
115 	{ NV( FL_BLANCHEDALMOND       ), 255, 235, 205, 0, 0 },
116 	{ NV( FL_BLUEVIOLET           ), 138,  43, 226, 0, 0 },
117 	{ NV( FL_BROWN                ), 165,  42,  42, 0, 0 },
118 	{ NV( FL_BURLYWOOD            ), 222, 184, 135, 0, 0 },
119 	{ NV( FL_CADETBLUE            ),  95, 158, 160, 0, 0 },
120 	{ NV( FL_CHOCOLATE            ), 210, 105,  30, 0, 0 },
121 	{ NV( FL_CORAL                ), 255, 127,  80, 0, 0 },
122 	{ NV( FL_CORNFLOWERBLUE       ), 100, 149, 237, 0, 0 },
123 	{ NV( FL_CORNSILK             ), 255, 248, 220, 0, 0 },
124 	{ NV( FL_CRIMSON              ), 220,  20,  60, 0, 0 },
125 	{ NV( FL_DARKBLUE             ),   0,   0, 139, 0, 0 },
126 	{ NV( FL_DARKGOLDENROD        ), 184, 134,  11, 0, 0 },
127 	{ NV( FL_DARKGRAY             ), 169, 169, 169, 0, 0 },
128 	{ NV( FL_DARKGREEN            ),   0, 100,   0, 0, 0 },
129 	{ NV( FL_DARKGREY             ), 169, 169, 169, 0, 0 },
130 	{ NV( FL_DARKKHAKI            ), 189, 183, 107, 0, 0 },
131 	{ NV( FL_DARKMAGENTA          ), 139,   0, 139, 0, 0 },
132 	{ NV( FL_DARKOLIVEGREEN       ),  85, 107,  47, 0, 0 },
133 	{ NV( FL_DARKORCHID           ), 153,  50, 204, 0, 0 },
134 	{ NV( FL_DARKRED              ), 139,   0,   0, 0, 0 },
135 	{ NV( FL_DARKSALMON           ), 233, 150, 122, 0, 0 },
136 	{ NV( FL_DARKSEAGREEN         ), 143, 188, 143, 0, 0 },
137 	{ NV( FL_DARKSLATEBLUE        ),  72,  61, 139, 0, 0 },
138 	{ NV( FL_DARKSLATEGRAY        ),  47,  79,  79, 0, 0 },
139 	{ NV( FL_DARKSLATEGREY        ),  47,  79,  79, 0, 0 },
140 	{ NV( FL_DARKTURQUOISE        ),   0, 206, 209, 0, 0 },
141 	{ NV( FL_DEEPSKYBLUE          ),   0, 191, 255, 0, 0 },
142 	{ NV( FL_DIMGRAY              ), 105, 105, 105, 0, 0 },
143 	{ NV( FL_DIMGREY              ), 105, 105, 105, 0, 0 },
144 	{ NV( FL_FIREBRICK            ), 178,  34,  34, 0, 0 },
145 	{ NV( FL_FLORALWHITE          ), 255, 250, 240, 0, 0 },
146 	{ NV( FL_FORESTGREEN          ),  34, 139,  34, 0, 0 },
147 	{ NV( FL_FUCHSIA              ), 255,   0, 255, 0, 0 },
148 	{ NV( FL_GAINSBORO            ), 220, 220, 220, 0, 0 },
149 	{ NV( FL_GHOSTWHITE           ), 248, 248, 255, 0, 0 },
150 	{ NV( FL_GOLD                 ), 255, 215,   0, 0, 0 },
151 	{ NV( FL_GOLDENROD            ), 218, 165,  32, 0, 0 },
152 	{ NV( FL_GRAY                 ), 128, 128, 128, 0, 0 },
153 	{ NV( FL_GREENYELLOW          ), 173, 255,  47, 0, 0 },
154 	{ NV( FL_GREY                 ), 128, 128, 128, 0, 0 },
155 	{ NV( FL_HONEYDEW             ), 240, 255, 240, 0, 0 },
156 	{ NV( FL_HOTPINK              ), 255, 105, 180, 0, 0 },
157 	{ NV( FL_INDIGO               ),  75,   0, 130, 0, 0 },
158 	{ NV( FL_IVORY                ), 255, 255, 240, 0, 0 },
159 	{ NV( FL_KHAKI                ), 240, 230, 140, 0, 0 },
160 	{ NV( FL_LAVENDER             ), 230, 230, 250, 0, 0 },
161 	{ NV( FL_LAVENDERBLUSH        ), 255, 240, 245, 0, 0 },
162 	{ NV( FL_LAWNGREEN            ), 124, 252,   0, 0, 0 },
163 	{ NV( FL_LEMONCHIFFON         ), 255, 250, 205, 0, 0 },
164 	{ NV( FL_LIGHTBLUE            ), 173, 216, 230, 0, 0 },
165 	{ NV( FL_LIGHTCORAL           ), 240, 128, 128, 0, 0 },
166 	{ NV( FL_LIGHTCYAN            ), 224, 255, 255, 0, 0 },
167 	{ NV( FL_LIGHTGOLDENRODYELLOW ), 250, 250, 210, 0, 0 },
168 	{ NV( FL_LIGHTGRAY            ), 211, 211, 211, 0, 0 },
169 	{ NV( FL_LIGHTGREEN           ), 144, 238, 144, 0, 0 },
170 	{ NV( FL_LIGHTGREY            ), 211, 211, 211, 0, 0 },
171 	{ NV( FL_LIGHTPINK            ), 255, 182, 193, 0, 0 },
172 	{ NV( FL_LIGHTSALMON          ), 255, 160, 122, 0, 0 },
173 	{ NV( FL_LIGHTSEAGREEN        ),  32, 178, 170, 0, 0 },
174 	{ NV( FL_LIGHTSKYBLUE         ), 135, 206, 250, 0, 0 },
175 	{ NV( FL_LIGHTSLATEGRAY       ), 119, 136, 153, 0, 0 },
176 	{ NV( FL_LIGHTSLATEGREY       ), 119, 136, 153, 0, 0 },
177 	{ NV( FL_LIGHTSTEELBLUE       ), 176, 196, 222, 0, 0 },
178 	{ NV( FL_LIGHTYELLOW          ), 255, 255, 224, 0, 0 },
179 	{ NV( FL_LIME                 ),   0, 255,   0, 0, 0 },
180 	{ NV( FL_LIMEGREEN            ),  50, 205,  50, 0, 0 },
181 	{ NV( FL_LINEN                ), 250, 240, 230, 0, 0 },
182 	{ NV( FL_MAROON               ), 128,   0,   0, 0, 0 },
183 	{ NV( FL_MEDIUMAQUAMARINE     ), 102, 205, 170, 0, 0 },
184 	{ NV( FL_MEDIUMBLUE           ),   0,   0, 205, 0, 0 },
185 	{ NV( FL_MEDIUMORCHID         ), 186,  85, 211, 0, 0 },
186 	{ NV( FL_MEDIUMPURPLE         ), 147, 112, 219, 0, 0 },
187 	{ NV( FL_MEDIUMSEAGREEN       ),  60, 179, 113, 0, 0 },
188 	{ NV( FL_MEDIUMSLATEBLUE      ), 123, 104, 238, 0, 0 },
189 	{ NV( FL_MEDIUMSPRINGGREEN    ),   0, 250, 154, 0, 0 },
190 	{ NV( FL_MEDIUMTURQUOISE      ),  72, 209, 204, 0, 0 },
191 	{ NV( FL_MEDIUMVIOLETRED      ), 199,  21, 133, 0, 0 },
192 	{ NV( FL_MIDNIGHTBLUE         ),  25,  25, 112, 0, 0 },
193 	{ NV( FL_MINTCREAM            ), 245, 255, 250, 0, 0 },
194 	{ NV( FL_MISTYROSE            ), 255, 228, 225, 0, 0 },
195 	{ NV( FL_MOCCASIN             ), 255, 228, 181, 0, 0 },
196 	{ NV( FL_NAVAJOWHITE          ), 255, 222, 173, 0, 0 },
197 	{ NV( FL_NAVY                 ),   0,   0, 128, 0, 0 },
198 	{ NV( FL_OLDLACE              ), 253, 245, 230, 0, 0 },
199 	{ NV( FL_OLIVE                ), 128, 128,   0, 0, 0 },
200 	{ NV( FL_OLIVEDRAB            ), 107, 142,  35, 0, 0 },
201 	{ NV( FL_ORANGE               ), 255, 165,   0, 0, 0 },
202 	{ NV( FL_ORANGERED            ), 255,  69,   0, 0, 0 },
203 	{ NV( FL_PALEGOLDENROD        ), 238, 232, 170, 0, 0 },
204 	{ NV( FL_PALETURQUOISE        ), 175, 238, 238, 0, 0 },
205 	{ NV( FL_PALEVIOLETRED        ), 219, 112, 147, 0, 0 },
206 	{ NV( FL_PAPAYAWHIP           ), 255, 239, 213, 0, 0 },
207 	{ NV( FL_PEACHPUFF            ), 255, 218, 185, 0, 0 },
208 	{ NV( FL_PERU                 ), 205, 133,  63, 0, 0 },
209 	{ NV( FL_PINK                 ), 255, 192, 203, 0, 0 },
210 	{ NV( FL_PLUM                 ), 221, 160, 221, 0, 0 },
211 	{ NV( FL_POWDERBLUE           ), 176, 224, 230, 0, 0 },
212 	{ NV( FL_PURPLE               ), 128,   0, 128, 0, 0 },
213 	{ NV( FL_ROSYBROWN            ), 188, 143, 143, 0, 0 },
214 	{ NV( FL_ROYALBLUE            ),  65, 105, 225, 0, 0 },
215 	{ NV( FL_SADDLEBROWN          ), 139,  69,  19, 0, 0 },
216 	{ NV( FL_SALMON               ), 250, 128, 114, 0, 0 },
217 	{ NV( FL_SANDYBROWN           ), 244, 164,  96, 0, 0 },
218 	{ NV( FL_SEAGREEN             ),  46, 139,  87, 0, 0 },
219 	{ NV( FL_SEASHELL             ), 255, 245, 238, 0, 0 },
220 	{ NV( FL_SIENNA               ), 160,  82,  45, 0, 0 },
221 	{ NV( FL_SILVER               ), 192, 192, 192, 0, 0 },
222 	{ NV( FL_SKYBLUE              ), 135, 206, 235, 0, 0 },
223 	{ NV( FL_SLATEGRAY            ), 112, 128, 144, 0, 0 },
224 	{ NV( FL_SLATEGREY            ), 112, 128, 144, 0, 0 },
225 	{ NV( FL_SNOW                 ), 255, 250, 250, 0, 0 },
226 	{ NV( FL_STEELBLUE            ),  70, 130, 180, 0, 0 },
227 	{ NV( FL_TAN                  ), 210, 180, 140, 0, 0 },
228 	{ NV( FL_TEAL                 ),   0, 128, 128, 0, 0 },
229 	{ NV( FL_THISTLE              ), 216, 191, 216, 0, 0 },
230 	{ NV( FL_TURQUOISE            ),  64, 224, 208, 0, 0 },
231 	{ NV( FL_VIOLET               ), 238, 130, 238, 0, 0 },
232 	{ NV( FL_WHITESMOKE           ), 245, 245, 245, 0, 0 },
233 	{ NV( FL_YELLOWGREEN          ), 154, 205,  50, 0, 0 },
234 	{ NV( FL_FREE_COL1            ),   0,   0,   0, 0, 0 },
235 	{ NV( FL_FREE_COL2            ),   0,   0,   0, 0, 0 },
236 	{ NV( FL_FREE_COL3            ),   0,   0,   0, 0, 0 },
237 	{ NV( FL_FREE_COL4            ),   0,   0,   0, 0, 0 },
238 	{ NV( FL_FREE_COL5            ),   0,   0,   0, 0, 0 },
239 	{ NV( FL_FREE_COL6            ),   0,   0,   0, 0, 0 },
240 	{ NV( FL_FREE_COL7            ),   0,   0,   0, 0, 0 },
241 	{ NV( FL_FREE_COL8            ),   0,   0,   0, 0, 0 },
242 	{ NV( FL_FREE_COL9            ),   0,   0,   0, 0, 0 },
243 	{ NV( FL_FREE_COL10           ),   0,   0,   0, 0, 0 },
244 	{ NV( FL_FREE_COL11           ),   0,   0,   0, 0, 0 },
245 	{ NV( FL_FREE_COL12           ),   0,   0,   0, 0, 0 },
246 	{ NV( FL_FREE_COL13           ),   0,   0,   0, 0, 0 },
247 	{ NV( FL_FREE_COL14           ),   0,   0,   0, 0, 0 },
248 	{ NV( FL_FREE_COL15           ),   0,   0,   0, 0, 0 },
249 	{ NV( FL_FREE_COL16           ),   0,   0,   0, 0, 0 },
250 };
251 
252 #define flmapsize ( ( int ) ( sizeof fli_imap / sizeof *fli_imap ) )
253 
254 
255 /***************************************
256  ***************************************/
257 
258 const char *
fli_query_colorname(FL_COLOR col)259 fli_query_colorname( FL_COLOR col )
260 {
261     FLI_IMAP *flmap;
262     static char buf[ 32 ];
263 
264     for ( flmap = fli_imap; flmap < fli_imap + FL_BUILT_IN_COLS + 1; flmap++ )
265         if ( col == flmap->index )
266             return flmap->name;
267 
268     /* Not a built-in */
269 
270     if ( col == FL_NoColor )
271         return "FL_NoColor";
272 
273     if ( col >= FL_FREE_COL1 && col <= FL_FREE_COL16 )
274         sprintf( buf,"FL_FREE_COL%ld",1+col-FL_FREE_COL1 );
275     else
276         sprintf( buf, "%ld", col );
277 
278     return buf;
279 }
280 
281 
282 /***************************************
283  ***************************************/
284 
285 long
fli_query_namedcolor(const char * s)286 fli_query_namedcolor( const char *s )
287 {
288     FLI_IMAP *flmap;
289 
290     if ( ! s )
291     {
292         M_err( "fli_query_namedcolor", "Null pointer for color name" );
293         return FL_MAX_COLORS + 1;
294     }
295 
296     for ( flmap = fli_imap; flmap < fli_imap + FL_BUILT_IN_COLS + 1; flmap++ )
297         if ( ! strcmp( s, flmap->name ) )
298             return flmap->index;
299 
300     if ( strstr( s, "FL_FREE_COL" ) )
301         return FL_FREE_COL1 + atoi( s + 11 ) - 1;
302 
303     if ( ! strcmp( "FL_NoColor", s ) )
304         return FL_NoColor;
305 
306     /* A wild shot */
307 
308     return atoi( s );
309 }
310 
311 
312 /***************************************
313  ***************************************/
314 
315 #ifdef DO_GAMMA_CORRECTION
316 
317 #include <math.h>
318 
319 
320 void
fl_set_gamma(double r,double g,double b)321 fl_set_gamma( double r,
322               double g,
323               double b )
324 {
325     FLI_IMAP *fm;
326     static double rgamma = 1.0,
327                   ggamma = 1.0,
328                   bgamma = 1.0;
329 
330     if ( fli_imap[ 4 ].grayval )
331     {
332         /* Too lazy to shuffle colormap around */
333 
334         M_err( "fl_set_gamma",
335                "Ignored. Please call fl_set_gamma before fl_initialize()" );
336         return;
337     }
338 
339     if ( r <= 1.e-3 || g <= 1.e-3 || b <= 1.e-3 )
340     {
341         M_warn( "fl_set_gamma", "BadValue %4.2f %4.2f %4.2f. Ignored",
342                 r, g, b );
343         return;
344     }
345 
346     for ( fm = fli_imap; fm < fli_imap + FL_BUILT_IN_COLS + 1; fm++ )
347     {
348         fm->r = 0.5 + 255 * pow( fm->r / 255.0, rgamma / r );
349         fm->g = 0.5 + 255 * pow( fm->g / 255.0, ggamma / g );
350         fm->b = 0.5 + 255 * pow( fm->b / 255.0, bgamma / b );
351     }
352 
353     rgamma = r;
354     ggamma = g;
355     bgamma = b;
356 }
357 
358 #endif /* DO_GAMMA_CORRECTION */
359 
360 
361 static XColor *defaultc = NULL;
362 
363 
364 /***************************************
365  * Copy the first several entries in the default colormap to avoid
366  * flashing in case we are using a private colormap or non-default
367  * visual (can't do anyting about TrueColor/DirectColor though)
368  ***************************************/
369 
370 #define DEFAULT_SAVE   35
371 
372 static int save_index[ ] = { 2, 3, 4, 5, 6, 7, 34 };
373 
374 #define NSAVE ( sizeof save_index / sizeof *save_index )
375 
376 static void
be_nice(void)377 be_nice( void )
378 {
379     int i,
380         save = FL_min( cols_in_default_visual - 210, DEFAULT_SAVE );
381     XColor *dc;
382     unsigned long newpixels[ DEFAULT_SAVE ],
383                   frees[ DEFAULT_SAVE ];
384     int npixels,
385         found,
386         j,
387         k,
388         saved;
389     FL_COLOR black = BlackPixel( flx->display, fl_screen );
390     FL_COLOR white = WhitePixel( flx->display, fl_screen );
391 
392     for ( saved = 0, dc = defaultc, i = 0; i < save; i++, dc++ )
393     {
394         dc->flags = DoRed | DoGreen | DoBlue;
395         if ( XAllocColor( flx->display, fli_colormap( fl_vmode ), dc ) )
396             newpixels[ saved++ ] = dc->pixel;
397     }
398 
399     /* Only keep the pixels in the save_index. 0 and 1 are always saved */
400 
401     for ( npixels = 0, i = 2; fli_depth( fl_vmode ) > 4 && i < saved; i++ )
402     {
403         k = newpixels[ i ];
404         for ( j = found = 0; ! found && j < ( int ) NSAVE; j++ )
405             found =     k == save_index[ j ]
406                      || k == ( int ) white
407                      || k == ( int ) black;
408 
409         if ( ! found )
410             frees[ npixels++ ] = k;
411     }
412 
413     if ( npixels )
414         XFreeColors( flx->display, fli_colormap( fl_vmode ),
415                      frees, npixels, 0 );
416 
417     if ( save <= 0 )
418     {
419         XColor xc;
420 
421         M_warn( "be_nice", "Black = %ld White = %ld", black, white );
422 
423         /* As a minimum, we should preserve black & white */
424 
425         xc.flags = DoRed | DoGreen | DoBlue;
426         if ( black == 0 )
427         {
428             xc.red = xc.green = xc.blue = 0;
429             xc.pixel = 0;
430             XAllocColor( flx->display, fli_colormap( fl_vmode ), &xc );
431             M_warn( "be_nice", "Get Black = %ld", xc.pixel );
432 
433             if ( white == 1 )
434             {
435                 xc.pixel = white;
436                 xc.red = xc.green = xc.blue = 0xffff;
437                 XAllocColor( flx->display, fli_colormap( fl_vmode ), &xc );
438                 M_warn( "be_nice", "Get White = %ld", xc.pixel );
439             }
440         }
441         else if ( white == 0 )
442         {
443             xc.red = xc.green = xc.blue = 0xffff;
444             XAllocColor( flx->display, fli_colormap( fl_vmode ), &xc );
445             M_warn( "be_nice", "Get White = %ld", xc.pixel );
446 
447             if ( black == 1 )
448             {
449                 xc.red = xc.green = xc.blue = black;
450                 xc.pixel = 0;
451                 XAllocColor( flx->display, fli_colormap( fl_vmode ), &xc );
452                 M_warn( "be_nice", "Get Black = %ld", xc.pixel );
453             }
454         }
455     }
456 
457     M_warn( "be_nice", "Total %d colors copied", save > 0 ? save : 2 );
458 }
459 
460 
461 /***************************************
462  ***************************************/
463 
464 static int
alloc_direct_color(void)465 alloc_direct_color( void )
466 {
467     XColor xxc[ FL_BUILT_IN_COLS ],
468            *xc;
469     FLI_IMAP *fm;
470     long pred = predefined_cols;
471 
472     for ( xc = xxc, fm = fli_imap; fm < fli_imap + pred; fm++, xc++ )
473     {
474         xc->red   = ( fm->r << 8 ) | 0xff;
475         xc->green = ( fm->g << 8 ) | 0xff;
476         xc->blue  = ( fm->b << 8 ) | 0xff;
477 
478         xc->flags = DoRed | DoGreen | DoBlue;
479         xc->pixel = lut[ fm->index ] = rgb2pixel( fm->r, fm->g, fm->b );
480     }
481 
482     XStoreColors( flx->display, fli_map( fl_vmode ), xxc, pred );
483 
484     return 1;
485 }
486 
487 
488 /***************************************
489  * Do colormap allocation. DirectColor is handled seperately
490  ***************************************/
491 
492 static int
fill_map(void)493 fill_map( void )
494 {
495     XColor xc;
496     int ok;
497     long pred = predefined_cols;
498     unsigned int r,
499                  g,
500                  b;
501     FLI_IMAP *fm,
502              *fs;
503 
504     lut = fl_state[ fl_vmode ].lut;
505     fli_dithered( fl_vmode ) = fli_depth( fl_vmode ) <= 2;
506 
507     M_warn( "fill_map", "Trying to get %d colors", pred );
508 
509     xc.flags = DoRed | DoGreen | DoBlue;
510 
511     for ( ok = 1, fm = fli_imap, fs = fm + pred; ok && fm < fs; fm++ )
512     {
513         /* If Xserver is grayscale, we are really walking the "gray" area as
514            the server can drive the the display with any of the r, g or b,
515            need to force a correct value */
516 
517         r = FL_is_gray( fl_vmode ) ? fm->grayval : fm->r;
518         g = FL_is_gray( fl_vmode ) ? fm->grayval : fm->g;
519         b = FL_is_gray( fl_vmode ) ? fm->grayval : fm->b;
520 
521         xc.red   = ( r << 8 ) | 0xff;
522         xc.green = ( g << 8 ) | 0xff;
523         xc.blue  = ( b << 8 ) | 0xff;
524 
525         ok = XAllocColor( flx->display, fli_map( fl_vmode ), &xc );
526         if ( ok )
527             lut[ fm->index ] = xc.pixel;
528     }
529 
530     if (    fl_state[ fl_vmode ].pcm
531          || fli_cntl.sharedColormap
532          || fli_dithered( fl_vmode ) )
533     {
534         if ( ! ok && fm > fli_imap )
535             fm--;
536         ok = 1;
537     }
538 
539     /* Get approx. for the rest of needed colors */
540 
541     for ( fs = fli_imap + FL_BUILT_IN_COLS; ok && fm < fs; fm++ )
542         fl_mapcolor( fm->index, fm->r, fm->g, fm->b );
543 
544     /* Make rest of the entry invalid so we don't accidently free a valid
545        pixel */
546 
547     memset( lut + FL_BUILT_IN_COLS, 1,
548             ( FL_MAX_COLS - FL_BUILT_IN_COLS ) * sizeof *lut );
549 
550     return ok;
551 }
552 
553 
554 /***************************************
555  * Try to get a private colormap. Return 1 for success. Typically
556  * this is the last color strategy we will try and in case it
557  * fails, caller probably should terminate the program.
558  ***************************************/
559 
560 static int
get_private_cmap(int vmode)561 get_private_cmap( int vmode )
562 {
563     int ok,
564         i;
565 
566     M_warn( "get_private_cmap", "getting private colormap" );
567 
568     /* Get a private colormap */
569 
570     fli_map( vmode ) = XCreateColormap( flx->display, fl_root,
571                                         fli_visual( vmode ),
572                                         vmode != FL_DirectColor ?
573                                         AllocNone : AllocAll );
574     if ( ! fli_map( vmode ) )
575     {
576         M_err( "get_private_cmap", "Can't create Colormap!" );
577         exit( 0 );
578     }
579 
580     lut = fl_state[ vmode ].lut;
581     if ( vmode == FL_DirectColor )
582         return alloc_direct_color( );
583 
584     /* Copy some default entries */
585 
586     be_nice( );
587 
588     /* Fill colormap with predetermined colors */
589 
590     fl_state[ vmode ].pcm = 1;
591     ok = fill_map( );
592 
593     for ( i = FL_BUILT_IN_COLS; i < FL_MAX_COLS; i++ )
594         lut[ i ] = i;
595 
596     M_warn( "get_private_cmap", "%s %s succesful",
597             fli_vclass_name( vmode ), ok ? "" : "not" );
598 
599     return ok;
600 }
601 
602 
603 /***************************************
604  * Use standard colormap only if user explicitly requests it as it
605  * is the most un-flexible among shared,private and standard.
606  ***************************************/
607 
608 static int
get_standard_cmap(int vmode)609 get_standard_cmap( int vmode )
610 {
611     FLI_IMAP *fm,
612              *fs;
613     XStandardColormap stdcmap;
614     XStandardColormap *sc = &stdcmap;
615     XColor xc;
616     Atom mapid = ( vmode == FL_GrayScale || vmode == FL_StaticGray ) ?
617                  XA_RGB_GRAY_MAP : XA_RGB_DEFAULT_MAP;
618 
619 #if FL_DEBUG >= ML_ERR
620     M_warn( "get_standard_cmap", "Getting standard colormap" );
621 #endif
622 
623     if ( ! XGetStandardColormap( flx->display, fl_root, &stdcmap, mapid ) )
624     {
625         M_err( "get_standard_cmap", "Can't get standard map" );
626         return 0;
627     }
628 
629     lut = fl_state[ vmode ].lut;
630 
631     /* we got the map. now figure out the pixel values */
632 
633     fli_map( vmode ) = sc->colormap;
634 
635     xc.flags = DoRed | DoGreen | DoBlue;
636     for ( fm = fli_imap, fs = fm + FL_BUILT_IN_COLS; fm < fs; fm++ )
637     {
638         xc.red   = ( fm->r << 8 ) | 0xff;
639         xc.green = ( fm->g << 8 ) | 0xff;
640         xc.blue  = ( fm->b << 8 ) | 0xff;
641         XAllocColor( flx->display, fli_colormap( vmode ), &xc );
642         lut[ fm->index ] = xc.pixel;
643     }
644 
645     fl_state[ vmode ].pcm = 1;
646     return 1;
647 }
648 
649 
650 /***************************************
651  ***************************************/
652 
653 static int
get_shared_cmap(int vmode)654 get_shared_cmap( int vmode )
655 {
656     int ok;
657 
658     /* Share colormap only if requested visual is the same as the default
659        visual */
660 
661     if ( fli_visual( vmode ) == DefaultVisual( flx->display, fl_screen ) )
662     {
663         fli_map( vmode ) = DefaultColormap( flx->display, fl_screen );
664         M_warn( "get_shared_cmap", "Using default map %ld for %s",
665                 fli_map( vmode ), fli_vclass_name( vmode ) );
666     }
667     else
668     {
669         fli_map( vmode ) = XCreateColormap( flx->display, fl_root,
670                                             fli_visual( vmode ),
671                                             vmode != FL_DirectColor ?
672                                             AllocNone : AllocAll );
673         M_warn( "get_shared_cmap", " NewMap %ld (0x%lx) for %s (ID = 0x%lx)",
674                 fli_map( vmode ), fli_map( vmode ), fli_vclass_name( vmode ),
675                 fli_visual( vmode )->visualid );
676     }
677 
678     if ( ! fli_map( vmode ) )
679     {
680         M_err( "get_shared_cmap", "Error getting colormaps" );
681         exit( 1 );
682     }
683 
684 #define PD( v )                                                          \
685     if ( ( DefaultVisual( flx->display, fl_screen ) )->class == ( v ) )  \
686         fprintf( stderr, "DefaultVisual = %s CurrentVisual = %s\n",          \
687                  #v, fli_vclass_name( fli_class( vmode ) ) );
688 
689     if ( fli_cntl.debug )
690     {
691         PD( TrueColor );
692         PD( PseudoColor );
693         PD( DirectColor );
694         PD( GrayScale );
695         PD( StaticGray );
696         PD( StaticColor );
697     }
698 
699     lut = fl_state[ vmode ].lut;
700 
701     if ( vmode == FL_DirectColor )
702         return alloc_direct_color( );
703 
704     /* Copy a few entries from the default colormap if we are using a map
705        other than the defaulf */
706 
707     if ( fli_visual( vmode ) != DefaultVisual( flx->display, fl_screen ) )
708         be_nice( );
709 
710     ok = fill_map( );
711 
712     /* If we can't do it, free the color we have already allocated so other
713        applications may have an easier time getting colors */
714 
715     if ( ! ok )
716     {
717         M_warn( "get_shared_cmap", "can't share for %s",
718                 fli_vclass_name( vmode ) );
719         fli_map( vmode ) = XCopyColormapAndFree( flx->display,
720                                                  fli_map( vmode ) );
721     }
722 
723     return ok;
724 }
725 
726 
727 /***************************************
728  * Create GCs for a particular visual and depth
729  ***************************************/
730 
731 void
fli_create_gc(Window win)732 fli_create_gc( Window win )
733 {
734     GC *flgcs,
735        *flgce;
736     FL_State *fs = fl_state + fl_vmode;
737 
738     /* If gc for this visual exists, do switch */
739 
740     if ( fl_state[ fl_vmode ].gc[ 0 ] )
741     {
742         flx->gc = fl_state[ fl_vmode ].gc[ 0 ];
743         flx->textgc = fl_state[ fl_vmode ].textgc[ 0 ];
744 
745         if ( fl_state[ fl_vmode ].cur_fnt )
746             XSetFont( flx->display, flx->textgc,
747                       fl_state[ fl_vmode ].cur_fnt->fid );
748         return;
749     }
750 
751     /* Check if we need to dither */
752 
753     fli_dithered( fl_vmode ) = fli_depth( fl_vmode ) <= 2;
754 
755     /* Need to create new GCs */
756 
757     M_warn( "fli_create_gc", "For %s", fli_vclass_name( fl_vmode ) );
758 
759     if ( ! fli_gray_pattern[ 1 ] )
760     {
761         M_err( "fli_create_gc", "gray pattern not initialized" );
762         exit( 1 );
763     }
764 
765     flgcs = fs->gc;
766     flgce = flgcs + sizeof fs->gc / sizeof *fs->gc;
767     for ( ; flgcs < flgce; flgcs++ )
768     {
769         *flgcs = XCreateGC( flx->display, win, 0, 0 );
770         XSetStipple( flx->display, *flgcs, FLI_INACTIVE_PATTERN );
771         XSetGraphicsExposures( flx->display, *flgcs, 0 );
772     }
773 
774     flx->gc = fl_state[ fl_vmode ].gc[ 0 ];
775 
776     /* Initialize text gc */
777 
778     flgcs = fs->textgc;
779     flgce = flgcs + sizeof fs->textgc / sizeof *fs->textgc;
780     for ( ; flgcs < flgce; flgcs++ )
781     {
782         *flgcs = XCreateGC( flx->display, win, 0, 0 );
783         XSetStipple( flx->display, *flgcs, FLI_INACTIVE_PATTERN );
784         XSetGraphicsExposures( flx->display, *flgcs, 0 );
785     }
786 
787     flx->textgc = fl_state[ fl_vmode ].textgc[ 0 ];
788 
789     /* Initialize a dimmed GC */
790 
791     fl_state[ fl_vmode ].dimmedGC = XCreateGC( flx->display, win, 0, 0 );
792     XSetStipple( flx->display, fl_state[ fl_vmode ].dimmedGC,
793                  FLI_INACTIVE_PATTERN );
794     XSetGraphicsExposures( flx->display, fl_state[ fl_vmode ].dimmedGC, 0 );
795     XSetFillStyle( flx->display, fl_state[ fl_vmode ].dimmedGC, FillStippled );
796 
797     /* Special for B&W and 2bits displays */
798 
799     if ( fli_dithered( fl_vmode ) )
800     {
801         int i;
802 
803         fli_whitegc = XCreateGC( flx->display, win, 0, 0 );
804         XSetForeground( flx->display, fli_whitegc, fl_get_flcolor( FL_WHITE ) );
805 
806         for ( i = 0; i < 3; i++ )
807         {
808             fli_bwgc[ i ] = XCreateGC( flx->display, win, 0, 0 );
809             XSetStipple( flx->display, fli_bwgc[ i ], fli_gray_pattern[ i ] );
810             XSetGraphicsExposures( flx->display, fli_bwgc[ i ], 0 );
811             XSetFillStyle( flx->display, fli_bwgc[ i ], FillStippled );
812         }
813     }
814 
815     if ( fl_state[ fl_vmode ].cur_fnt )
816         XSetFont( flx->display, flx->textgc,
817                   fl_state[ fl_vmode ].cur_fnt->fid );
818 }
819 
820 
821 
822 /***************************************
823  *  Global routine to initialize all things related visual and colors
824  ***************************************/
825 
826 void
fli_init_colormap(int vmode)827 fli_init_colormap( int vmode )
828 {
829     int i,
830         ok;
831     FLI_IMAP *fm = fli_imap;
832     Colormap defmap;
833 
834     /* If map for this mode already exists, leave it alone, not only
835        efficient but also necessary as fl_win_open may call init map */
836 
837     if ( fli_map( vmode ) )
838     {
839 #if FL_DEBUG >= ML_DEBUG
840         M_info( "fli_init_colormap", "%s is ok", fli_vclass_name( vmode ) );
841 #endif
842         return;
843     }
844 
845     /* Get max colors we can have, take care there are machines where an
846        unsigned long isn't large enough to hold the number of colors) */
847 
848     if ( ( unsigned int ) fli_depth( vmode ) >=
849                                              CHAR_BIT * sizeof max_server_cols )
850         max_server_cols = ~ 0;
851     else
852         max_server_cols = 1L << fli_depth( vmode );
853 
854     predefined_cols = FL_min( FL_BUILT_IN_COLS, max_server_cols );
855     M_info( "fli_init_colormap", "MaxColors = %d PredefCol = %d",
856             max_server_cols, predefined_cols );
857 
858     fli_init_stipples( );
859 
860     if ( ! defaultc )
861         defaultc = fl_malloc( FL_MAX_COLS * sizeof *defaultc );
862 
863     /* Initialize secondary lookup table */
864 
865     for ( fm = fli_imap, i = 0; i < FL_MAX_COLS; i++, fm++ )
866     {
867         defaultc[ i ].pixel = i;
868         fm->grayval = FL_RGB2GRAY( fm->r, fm->g, fm->b );
869         if ( i >= FL_BUILT_IN_COLS )
870             fm->index = i;
871     }
872 
873     /* Take a snapshot of the default colormap for later use by
874        private_colormap */
875 
876     defmap = DefaultColormap( flx->display, fl_screen );
877     cols_in_default_visual =
878                           ( 1L << DefaultDepth( flx->display, fl_screen ) ) - 1;
879 
880     /* Some server may have a default visual with depth == 32 */
881 
882     if ( cols_in_default_visual <= 0 )
883         cols_in_default_visual = 80;
884 
885     M_warn( "fli_init_colormap", "%ld (0x%lx)", defmap, defmap );
886 
887     XQueryColors( flx->display, defmap, defaultc,
888                   FL_min( cols_in_default_visual, DEFAULT_SAVE ) );
889 
890     ok = 0;
891 
892     if ( fli_cntl.privateColormap )
893         ok = get_private_cmap( vmode );
894     else if ( fli_cntl.standardColormap )
895         ok = get_standard_cmap( vmode );
896 
897     if ( ! ok && ! ( ok = get_shared_cmap( vmode ) ) )
898     {
899         /* If unable to share colormaps, we can either get a private colormap
900            or force substitutions */
901 #if 1
902         M_err( "fli_init_colormap",
903                "Failed to share colors. Using private colormap" );
904         ok = get_private_cmap( vmode );
905 #else
906         ok = 1;
907         fli_cntl.sharedColormap = 1;
908         get_shared_cmap( vmode );
909 #endif
910     }
911 
912     if ( ! ok )
913     {
914         M_err( "fli_init_colormap",
915                "I screwed up or you have a weird workstatation" );
916         exit( 1 );
917     }
918 
919     M_warn( "fli_init_colormap", "%s Done", fli_vclass_name( vmode ) );
920 
921 #if FL_DEBUG >= ML_WARN
922     fli_dump_state_info( vmode, "fli_init_colormap" );
923 #endif
924 }
925 
926 
927 /***************************************
928  ***************************************/
929 
930 void
fli_free_colormap(int vmode)931 fli_free_colormap( int vmode )
932 {
933     int i;
934 
935     for( i = 0; i < 3; i++ )
936         if ( fli_gray_pattern[ i ] )
937         {
938             XFreePixmap( flx->display, fli_gray_pattern[ i ] );
939             fli_gray_pattern[ i ] = None;
940         }
941 
942     if ( fli_visual( vmode ) != DefaultVisual( flx->display, fl_screen ) )
943         XFreeColormap( flx->display, fli_map( vmode ) );
944 
945     fli_safe_free( defaultc );
946 }
947 
948 
949 
950 static unsigned long
951 get_rgb_pixel( FL_COLOR packed,
952                int *    newpix );
953 
954 
955 /***************************************
956  * Input col is an XForms color, e.g. FL_RED etc. The
957  * return value is the true pixel value X understands.
958  ***************************************/
959 
960 unsigned long
fl_get_pixel(FL_COLOR col)961 fl_get_pixel( FL_COLOR col )
962 {
963     if ( col == FL_NoColor )
964         return fl_get_pixel( FL_COL1 );
965 
966     if ( flx->isRGBColor )
967         return get_rgb_pixel( col, &flx->newpix );
968 
969     if ( col >= FL_MAX_COLS )
970     {
971         M_err( "fl_get_pixel", "Bad request %lu", col );
972         return 0;
973     }
974 
975     return fl_state[ fl_vmode ].lut[ col ];
976 }
977 
978 
979 /***************************************
980  ***************************************/
981 
982 void
fl_set_foreground(GC gc,FL_COLOR color)983 fl_set_foreground( GC       gc,
984                    FL_COLOR color )
985 {
986     XSetForeground( fl_display, gc, fl_get_pixel( color ) );
987 }
988 
989 
990 /***************************************
991  ***************************************/
992 
993 void
fl_set_background(GC gc,FL_COLOR color)994 fl_set_background( GC       gc,
995                    FL_COLOR color )
996 {
997     XSetBackground( fl_display, gc, fl_get_pixel( color ) );
998 }
999 
1000 
1001 /***************************************
1002  ***************************************/
1003 
1004 void
fl_color(FL_COLOR col)1005 fl_color( FL_COLOR col )
1006 {
1007     static int vmode = -1;
1008 
1009     if ( flx->color != col || vmode != fl_vmode )
1010     {
1011         unsigned long p = fl_get_pixel( col );
1012 
1013         flx->color = col;
1014         vmode = fl_vmode;
1015         XSetForeground( flx->display, flx->gc, p );
1016         fli_free_newpixel( p );
1017     }
1018 }
1019 
1020 
1021 /***************************************
1022  ***************************************/
1023 
1024 static unsigned long
get_rgb_pixel(FL_COLOR packed,int * newpix)1025 get_rgb_pixel( FL_COLOR   packed,
1026                int      * newpix )
1027 {
1028     FL_STATE *s = &fl_state[ fl_vmode ];
1029     unsigned long pixel;
1030     static Colormap lastcolormap;
1031     static XColor *xcolor;
1032     static int new_col;
1033     XColor xc;
1034 
1035     unsigned int r = FL_GETR( packed );
1036     unsigned int g = FL_GETG( packed );
1037     unsigned int b = FL_GETB( packed );
1038 
1039     *newpix = 0;
1040     if ( s->vclass == TrueColor || s->vclass == DirectColor )
1041         return rgb2pixel( r, g, b );
1042     else
1043     {
1044         int max_col;
1045 
1046         xc.flags = DoRed | DoGreen | DoBlue;
1047         xc.red   = ( r << 8 ) | 0xff;
1048         xc.green = ( g << 8 ) | 0xff;
1049         xc.blue  = ( b << 8 ) | 0xff;
1050 
1051         new_col++;
1052 
1053         if ( ( *newpix = XAllocColor( flx->display, s->colormap, &xc ) ) )
1054             return xc.pixel;
1055 
1056         /* Color allocation failed. Search for best match */
1057 
1058         if ( ( max_col = FL_min( 256, 1 << s->depth ) ) == 0 )
1059             max_col = 256;
1060 
1061         if ( ! xcolor )
1062             xcolor = fl_malloc( 256 * sizeof *xcolor );
1063 
1064         /* Not theoretically correct as colormap may have changed
1065          * since the last time we asked for colors. Take a chance for
1066          * performace. */
1067 
1068         if ( lastcolormap != s->colormap || new_col > 3 )
1069         {
1070             int i;
1071 
1072             for ( i = 0; i < max_col; i++ )
1073                 xcolor[ i ].pixel = i;
1074             XQueryColors( flx->display, s->colormap, xcolor, max_col );
1075             lastcolormap = s->colormap;
1076             new_col = 0;
1077         }
1078 
1079         fli_find_closest_color( r, g, b, xcolor, max_col, &pixel );
1080         return pixel;
1081     }
1082 }
1083 
1084 
1085 /***************************************
1086  ***************************************/
1087 
1088 static void
fli_free_newpixel(unsigned long pixel)1089 fli_free_newpixel( unsigned long pixel )
1090 {
1091     if ( flx->newpix )
1092     {
1093         XFreeColors( flx->display, flx->colormap, &pixel, 1, 0 );
1094         flx->newpix = 0;
1095     }
1096 }
1097 
1098 
1099 /***************************************
1100  ***************************************/
1101 
1102 void
fli_textcolor(FL_COLOR col)1103 fli_textcolor( FL_COLOR col )
1104 {
1105     static int vmode = -1;
1106     static int switched;
1107     static GC textgc;
1108 
1109     if (    flx->textcolor != col
1110          || vmode != fl_vmode
1111          || flx->textcolor == lastmapped )
1112     {
1113         unsigned long p;
1114 
1115         lastmapped = FL_NoColor;
1116 
1117         flx->textcolor = col;
1118 
1119         vmode = fl_vmode;
1120         if ( col == FL_INACTIVE_COL && fli_dithered( vmode ) )
1121         {
1122             textgc = flx->textgc;
1123             flx->textgc = fl_state[ vmode ].dimmedGC;
1124             XSetFont( flx->display, flx->textgc,
1125                       fl_state[ vmode ].cur_fnt->fid );
1126             switched = 1;
1127         }
1128         else if ( switched )
1129         {
1130             flx->textgc = textgc;
1131             XSetFont( flx->display, flx->textgc,
1132                       fl_state[ vmode ].cur_fnt->fid );
1133             switched = 0;
1134         }
1135 
1136         p = fl_get_pixel( col );
1137         XSetForeground( flx->display, flx->textgc, p );
1138         fli_free_newpixel( p );
1139     }
1140 }
1141 
1142 
1143 /***************************************
1144  * Set the background color for drawing
1145  ***************************************/
1146 
1147 void
fl_bk_color(FL_COLOR col)1148 fl_bk_color( FL_COLOR col )
1149 {
1150     if ( flx->bkcolor != col )
1151     {
1152         unsigned long p = fl_get_pixel( col );
1153 
1154         flx->bkcolor = col;
1155         XSetBackground( flx->display, flx->gc, p );
1156         fli_free_newpixel( p );
1157     }
1158 }
1159 
1160 
1161 /***************************************
1162  * Set the background color for text
1163  ***************************************/
1164 
1165 void
fli_bk_textcolor(FL_COLOR col)1166 fli_bk_textcolor( FL_COLOR col )
1167 {
1168     if ( flx->bktextcolor != col )
1169     {
1170         unsigned long p = fl_get_pixel( col );
1171         flx->bktextcolor = col;
1172         XSetBackground( flx->display, flx->textgc, p );
1173         fli_free_newpixel( p );
1174     }
1175 }
1176 
1177 
1178 /***************************************
1179  * Map color: it involves changing the internal colormap as well as
1180  * requesting the acutal pixel value. In case a request fails,
1181  * we subsititute the closest color
1182  ***************************************/
1183 
1184 unsigned long
fl_mapcolor(FL_COLOR col,int r,int g,int b)1185 fl_mapcolor( FL_COLOR col,
1186              int      r,
1187              int      g,
1188              int      b )
1189 {
1190     XColor exact;
1191     int i, j = -1;
1192     static int totalcols;
1193     static XColor *cur_mapvals[ 6 ],
1194                   *cur_map;
1195     unsigned long pixel;
1196 
1197     /* If requested color is reserved, warn */
1198 
1199     if ( col < FL_BUILT_IN_COLS )
1200         M_warn( "fl_mapcolor", "Changing reserved color" );
1201 
1202     /* Must invalidate color cache */
1203 
1204     if ( col == flx->color )
1205         flx->color = BadPixel;
1206 
1207     lut = fl_state[ fl_vmode ].lut;
1208 
1209     if ( col >= flmapsize )
1210     {
1211         M_err( "fl_mapcolor",
1212                "Only %d indexed colors are supported", flmapsize );
1213         return 0;
1214     }
1215 
1216     /* col is the external colorname, FL_RED etc, which is kept in
1217        fli_imap[].index. */
1218 
1219     if ( col == fli_imap[ col ].index )
1220         j = col;
1221 
1222     for ( i = 0; j < 0 && i < flmapsize; i++ )
1223         if ( col == fli_imap[ i ].index )
1224             j = i;
1225 
1226     if ( j < 0 )
1227         j = flmapsize - 1;
1228 
1229     /* In B&W too many colors collaps together */
1230 
1231     if (    fli_imap[ j ].r == r
1232          && fli_imap[ j ].g == g
1233          && fli_imap[ j ].b == b
1234          && r != 0
1235          && ! fli_dithered( fl_vmode )
1236          && lut[ col ] )
1237         return lut[ col ];
1238 
1239     fli_imap[ j ].r       = r;
1240     fli_imap[ j ].g       = g;
1241     fli_imap[ j ].b       = b;
1242     fli_imap[ j ].grayval = FL_RGB2GRAY( r, g, b );
1243     fli_imap[ j ].index   = col;
1244 
1245     lastmapped = col;
1246 
1247     M_warn( "fl_mapcolor", "mapping %ld (%d,%d,%d)", col, r, g, b );
1248 
1249     pixel       = lut[ col ];
1250     exact.red   = ( r << 8 ) | 0xff;
1251     exact.green = ( g << 8 ) | 0xff;
1252     exact.blue  = ( b << 8 ) | 0xff;
1253     exact.flags = DoRed | DoGreen | DoBlue;
1254     exact.pixel = pixel;
1255 
1256     if ( fl_vmode == DirectColor )
1257     {
1258         exact.pixel = lut[ col ] = rgb2pixel( r, g, b );
1259         XStoreColors( flx->display, fli_map( fl_vmode ), &exact, 1 );
1260         return lut[ col ];
1261     }
1262 
1263     /* pixel value known by the server */
1264 
1265     if ( ! allow_leakage && fli_depth( fl_vmode ) >= 4 && pixel != BadPixel )
1266         fl_free_pixels( &pixel, 1 );
1267 
1268     if ( XAllocColor( flx->display, fli_colormap( fl_vmode ), &exact ) )
1269     {
1270         lut[ col ] = exact.pixel;
1271         return lut[ col ];
1272     }
1273 
1274     /* Colormap is full. Warn once and substitute from now on */
1275 
1276     if ( ! cur_mapvals[ fl_vmode ] )
1277     {
1278         M_warn( "fl_mapcolor", "ColormapFull. Using substitutions" );
1279 
1280         totalcols = FL_min( FL_MAX_COLS, 1L << fli_depth( fl_vmode ) );
1281         cur_map = fl_calloc( totalcols + 1, sizeof *cur_map );
1282         cur_mapvals[ fl_vmode ] = cur_map;
1283 
1284         /* Take a snapshot of the color map */
1285 
1286         for ( i = 0; i < totalcols; i++ )
1287             cur_map[ i ].pixel = i;
1288 
1289         XQueryColors( flx->display, fli_map( fl_vmode ), cur_map, totalcols );
1290     }
1291 
1292     /* Search for the closest match */
1293 
1294     cur_map = cur_mapvals[ fl_vmode ];
1295     j = fli_find_closest_color( r, g, b, cur_map, totalcols, &pixel );
1296 
1297     if ( j < 0 )
1298     {
1299         M_err( "fl_mapcolor", "Something is very wrong" );
1300         exit( 1 );
1301     }
1302 
1303     /* j will be the stuff we want */
1304 
1305     lut[ col ] = cur_map[ j ].pixel;
1306 
1307     /* We still need to allocate the color, otherwise destroying the just
1308        requested color might accidentally free a reserved pixel */
1309 
1310     exact.red   = cur_map[ j ].red;
1311     exact.green = cur_map[ j ].green;
1312     exact.blue  = cur_map[ j ].blue;
1313     exact.pixel = cur_map[ j ].pixel;
1314     exact.flags = DoRed | DoGreen | DoBlue;
1315 
1316     if ( ! XAllocColor( flx->display, fli_colormap( fl_vmode ), &exact ) )
1317         M_warn( "fl_mapcolor", "Something is wrong - will proceed" );
1318 
1319 
1320 #if FL_DEBUG >= ML_DEBUG
1321     M_warn( "fl_mapcolor", "(%d %d %d)<->(%d %d %d)",
1322             r, g, b, cur_map[ j ].red, cur_map[ j ].green, cur_map[ j ].blue );
1323 #endif
1324 
1325     return lut[ col ];
1326 }
1327 
1328 
1329 /***************************************
1330  ***************************************/
1331 
1332 long
fl_mapcolorname(FL_COLOR col,const char * name)1333 fl_mapcolorname( FL_COLOR     col,
1334                  const char * name )
1335 {
1336     XColor xc;
1337 
1338     if ( XParseColor( flx->display, fli_colormap( fl_vmode ),
1339                       ( char * ) name, &xc ) )
1340     {
1341         xc.red   = ( xc.red   >> 8 ) & 0xff;
1342         xc.green = ( xc.green >> 8 ) & 0xff;
1343         xc.blue  = ( xc.blue  >> 8 ) & 0xff;
1344         return fl_mapcolor( col, xc.red, xc.green, xc.blue );
1345     }
1346 
1347     return -1;
1348 }
1349 
1350 
1351 /***************************************
1352  * change internal colormap before initialization. This way,
1353  * FORMS default color can be changed
1354  ***************************************/
1355 
1356 void
fl_set_icm_color(FL_COLOR col,int r,int g,int b)1357 fl_set_icm_color( FL_COLOR col,
1358                   int      r,
1359                   int      g,
1360                   int      b )
1361 {
1362     int i;
1363 
1364     for ( i = 0; i < flmapsize; i++ )
1365         if ( col == fli_imap[ i ].index )
1366         {
1367             if ( FL_is_gray( fl_vmode ) )
1368                 fli_imap[ i ].grayval = FL_RGB2GRAY( r, g, b );
1369             else
1370             {
1371                 fli_imap[ i ].r = r;
1372                 fli_imap[ i ].g = g;
1373                 fli_imap[ i ].b = b;
1374             }
1375 
1376             return;
1377         }
1378 }
1379 
1380 
1381 /***************************************
1382  * query internal  colormap
1383  ***************************************/
1384 
1385 void
fl_get_icm_color(FL_COLOR col,int * r,int * g,int * b)1386 fl_get_icm_color( FL_COLOR col,
1387                   int *    r,
1388                   int *    g,
1389                   int *    b )
1390 {
1391     int i;
1392 
1393     for ( i = 0; i < flmapsize; i++ )
1394         if ( col == fli_imap[ i ].index )
1395         {
1396             if ( FL_is_gray( fl_vmode ) )
1397                 *r = *g = *b = fli_imap[ i ].grayval;
1398             else
1399             {
1400                 *r = fli_imap[ i ].r;
1401                 *g = fli_imap[ i ].g;
1402                 *b = fli_imap[ i ].b;
1403             }
1404 
1405             return;
1406         }
1407 }
1408 
1409 
1410 /***************************************
1411  * query real colormap. r,g,b returned is the current color used
1412  ***************************************/
1413 
1414 unsigned long
fl_getmcolor(FL_COLOR i,int * r,int * g,int * b)1415 fl_getmcolor( FL_COLOR i,
1416               int *    r,
1417               int *    g,
1418               int *    b )
1419 {
1420     XColor exact;
1421 
1422     if ( ( exact.pixel = fl_get_pixel( i ) ) >= max_server_cols )
1423     {
1424         *r = *g = *b = 0;
1425         return ( unsigned long ) -1;
1426     }
1427 
1428     XQueryColor( flx->display, fli_map( fl_vmode ), &exact );
1429 
1430     *r = ( exact.red   >> 8 ) & 0xff;
1431     *g = ( exact.green >> 8 ) & 0xff;
1432     *b = ( exact.blue  >> 8 ) & 0xff;
1433 
1434     return exact.pixel;
1435 }
1436 
1437 
1438 /*** End of Colormap routines  *******}***************/
1439 
1440 
1441 /***************************************
1442  ***************************************/
1443 
1444 int
fl_get_visual_depth(void)1445 fl_get_visual_depth( void )
1446 {
1447     return fl_state[ fl_vmode ].depth;
1448 }
1449 
1450 
1451 /***************************************
1452  * print out the current state info. For debugging only
1453  ***************************************/
1454 
1455 #if FL_DEBUG >= ML_WARN
1456 void
fli_dump_state_info(int mode,const char * where)1457 fli_dump_state_info( int          mode,
1458                      const char * where )
1459 {
1460     FL_State *fs = fl_state + mode;
1461     XVisualInfo xvi;
1462 
1463     if ( fli_cntl.debug )
1464     {
1465         fprintf( stderr, "In %s", where );
1466         fprintf( stderr, " VClass: %s", fli_vclass_name( fli_class( mode ) ) );
1467         fprintf( stderr, " VisualID: 0x%lx", fs->xvinfo->visualid );
1468         fprintf( stderr, " Depth: %d %d",
1469                  fli_depth( mode ), fs->xvinfo->depth );
1470         fprintf( stderr, " Colormap: 0x%lx\n", fli_map( mode ) );
1471     }
1472 
1473     /* Some more checks */
1474 
1475     if ( ! XMatchVisualInfo( flx->display, fl_screen, fli_depth( mode ),
1476                              fli_class( mode ), &xvi ) )
1477     {
1478         M_err( "fli_dump_state_info", "Can't match listed visual" );
1479         exit( 1 );
1480     }
1481 
1482     /* Possible on SGI with OpenGL selected visuals */
1483 
1484     if ( fli_visual( mode )->visualid != xvi.visualid )
1485 
1486         M_warn( "fli_dump_state_info", "inconsistent visualID, probably OK" );
1487 
1488     /* State info consistency */
1489 
1490     if ( fli_depth( mode ) != fs->xvinfo->depth )
1491     {
1492         M_err( "fli_dump_state_info", "Bad Depth" );
1493         exit( 1 );
1494     }
1495 
1496     if ( fli_class( mode ) != fs->xvinfo->class )
1497     {
1498         M_err( "fli_dump_state_info", "Bad visual class" );
1499         exit( 1 );
1500     }
1501 }
1502 #endif
1503 
1504 
1505 /***************************************
1506  ***************************************/
1507 
1508 int
fl_mode_capable(int mode,int warn)1509 fl_mode_capable( int mode,
1510                  int warn )
1511 {
1512     int cap;
1513 
1514     if ( mode < 0 || mode > 5 )
1515     {
1516         M_err( "fl_mode_capable", "Bad mode = %d", mode );
1517         return 0;
1518     }
1519 
1520     cap = fli_depth( mode ) >= FL_MINDEPTH && fli_visual( mode );
1521 
1522     if ( ! cap && warn )
1523         M_warn( "fl_mode_capable", "Not capable of %s at depth = %d",
1524                 fli_vclass_name( mode ), fli_depth( mode ) );
1525 
1526     return cap;
1527 }
1528 
1529 
1530 /***************************************
1531  * Convert a RGB triple into a pixel value usable in DirectColor
1532  * and TrueColor. Note the RGB triple is ONE-BYTE EACH.
1533  ***************************************/
1534 
1535 static FL_COLOR
rgb2pixel(unsigned int r,unsigned int g,unsigned int b)1536 rgb2pixel( unsigned int r,
1537            unsigned int g,
1538            unsigned int b )
1539 {
1540     FL_State *s = fl_state + fl_vmode;
1541 
1542     /* This one drops bits and looks bad if primary color resolution is less
1543        than 6, but server calculates color this way. A better way  should be
1544        r = ((float) r * ((1L << s->rbits) - 1) / 255.0 + 0.1); */
1545 
1546     if ( s->rbits < 8 )
1547     {
1548         r >>= 8 - s->rbits;
1549         g >>= 8 - s->gbits;
1550         b >>= 8 - s->bbits;
1551     }
1552     else if ( s->rbits > 8 )
1553     {
1554         r <<= 8 - s->rbits;
1555         g <<= 8 - s->gbits;
1556         b <<= 8 - s->bbits;
1557     }
1558 
1559     return   ( ( ( unsigned long ) r << s->rshift ) & s->rmask )
1560            | ( ( ( unsigned long ) g << s->gshift ) & s->gmask )
1561            | ( ( ( unsigned long ) b << s->bshift ) & s->bmask );
1562 }
1563 
1564 
1565 /***************************************
1566  * Create a colormap valid for the given visual. It also
1567  * fills the colormap with default XFORMS map
1568  ***************************************/
1569 
1570 #define MAXFILL   ( FL_BUILT_IN_COLS + 1 )
1571 #define MAXREAD   100
1572 
1573 Colormap
fl_create_colormap(XVisualInfo * xv,int nfill)1574 fl_create_colormap( XVisualInfo * xv,
1575                     int           nfill )
1576 {
1577     long black = BlackPixel( flx->display, fl_screen );
1578     long white = WhitePixel( flx->display, fl_screen );
1579     XColor xc;
1580     Colormap cmap;
1581     int depth = xv->depth == 32 ? 24:xv->depth;
1582     int maxcolors = 1 << depth;
1583     int maxread = FL_min( MAXREAD, maxcolors );
1584     XColor *cur_entries = fl_malloc( maxread * sizeof *cur_entries ),
1585            *dc;
1586     unsigned long pixels[ MAXREAD ],
1587                   allocated[ MAXREAD ];
1588     int keep = maxcolors / 32;
1589 
1590     cmap = XCreateColormap( flx->display, fl_root, xv->visual,
1591                             xv->class != FL_DirectColor ?
1592                             AllocNone : AllocAll );
1593 
1594     /* As a minimum try to preserve Black or White */
1595 
1596     xc.flags = DoRed | DoGreen | DoBlue;
1597     xc.pixel = 0;
1598     if ( black == 0 && nfill >= 0 )
1599     {
1600         xc.red = xc.green = xc.blue = 0;
1601         XAllocColor( flx->display, cmap, &xc );
1602     }
1603     else if ( white == 0 && nfill >= 0 )
1604     {
1605         xc.red = xc.green = xc.blue = 0xffff;
1606         XAllocColor( flx->display, cmap, &xc );
1607     }
1608 
1609     /* Now if have the same visual, we can do event more */
1610 
1611     if ( nfill > 0 && fl_vmode == xv->class && fl_vmode != DirectColor )
1612     {
1613         int i,
1614             k;
1615 
1616         nfill = FL_min( MAXFILL, nfill );
1617         nfill = FL_min( nfill, maxcolors );
1618 
1619         if ( nfill < 4 )        /* potentially 8+1+4 colors */
1620             nfill = 4;
1621 
1622         for ( i = 0; i < maxread; i++ )
1623             cur_entries[ i ].pixel = i;
1624 
1625         XQueryColors( flx->display, fli_map( fl_vmode ), cur_entries, maxread );
1626 
1627         dc = cur_entries;
1628         for ( k = i = 0; i < maxread; i++, dc++ )
1629         {
1630             allocated[ i ] = FL_NoColor;
1631             dc->flags = DoRed | DoGreen | DoBlue;
1632             if ( XAllocColor( flx->display, cmap, dc ) )
1633                 allocated[ k++ ] = dc->pixel;
1634         }
1635 
1636         /* Now free the non-xforms colors, but keep some non-xforms entries */
1637 
1638         for ( k = 0, i = keep; i < maxread; i++ )
1639         {
1640             unsigned int p = allocated[ i ];
1641             int j,
1642                 found;
1643 
1644             for ( j = found = 0; ! found && j < nfill; j++ )
1645                 found =    p == fl_get_pixel( j )
1646                         || p == ( unsigned long ) white
1647                         || p == ( unsigned long ) black
1648                         || p == 34;
1649 
1650             if ( ! found && p != FL_NoColor )
1651                 pixels[ k++ ] = p;
1652         }
1653 
1654         if ( k )
1655         {
1656             M_warn( "fl_create_colormap", "free %d\n", k );
1657             XFreeColors( flx->display, cmap, pixels, k, 0 );
1658         }
1659     }
1660 
1661     fl_free( cur_entries );
1662     return cmap;
1663 }
1664 
1665 
1666 /***************************************
1667  ***************************************/
1668 
1669 void
fl_set_color_leak(int y)1670 fl_set_color_leak( int y )
1671 {
1672     allow_leakage = y;
1673 }
1674 
1675 
1676 /***************************************
1677  * if an index is being for the first time, the corresponding pixel
1678  * is either reserverd or bad, need to trap it
1679  ***************************************/
1680 
1681 static int
bad_color_handler(Display * d FL_UNUSED_ARG,XErrorEvent * xev)1682 bad_color_handler( Display     * d    FL_UNUSED_ARG,
1683                    XErrorEvent * xev )
1684 {
1685     if ( xev->error_code == BadAccess )
1686         M_warn( "bad_color_handler", "bad pixel" );
1687 
1688     return 0;
1689 }
1690 
1691 
1692 /***************************************
1693  ***************************************/
1694 
1695 void
fl_free_pixels(unsigned long * pix,int n)1696 fl_free_pixels( unsigned long * pix,
1697                 int             n )
1698 {
1699     int ( *oh )( Display *, XErrorEvent * );
1700 
1701     oh = XSetErrorHandler( bad_color_handler );
1702     XFreeColors( flx->display, fli_map( fl_vmode ), pix, n, 0 );
1703     XSync( flx->display, 0 );
1704     XSetErrorHandler( oh );
1705 }
1706 
1707 
1708 /***************************************
1709  ***************************************/
1710 
1711 void
fl_free_colors(FL_COLOR * c,int n)1712 fl_free_colors( FL_COLOR * c,
1713                 int        n )
1714 {
1715     int i,
1716         k,
1717         j = -1;
1718     unsigned long * pixels = fl_malloc( n * sizeof *pixels ),
1719                   *pix;
1720 
1721     lut = fl_state[ fl_vmode ].lut;
1722     pix = pixels;
1723 
1724     for ( k = 0; k < n; k++, c++, pix++ )
1725     {
1726         /* If requested color is reserved, warn */
1727 
1728         if ( *c < FL_FREE_COL1 )
1729             M_warn( "fl_free_colors", "Freeing reserved color" );
1730 
1731         /* Must invalidate color cache */
1732 
1733         if ( *c == flx->color )
1734             flx->color = BadPixel;
1735 
1736         for ( i = 0; j < 0 && i < flmapsize; i++ )
1737             if ( *c == fli_imap[ i ].index )
1738                 j = i;
1739 
1740         if ( j < 0 )
1741             j = flmapsize - 1;
1742 
1743         /* Pixel value known by the server */
1744 
1745         *pix = lut[ *c ];
1746 
1747         /* Mark this pixel as bad */
1748 
1749         lut[ *c ] = BadPixel;
1750     }
1751 
1752     fl_free_pixels( pixels, n );
1753     fl_free( pixels );
1754 }
1755 
1756 
1757 /***************************************
1758  * (r,g,b) input should be 8bit each
1759  ***************************************/
1760 
1761 #define LINEAR_COLOR_DISTANCE  0
1762 
1763 int
fli_find_closest_color(int r,int g,int b,XColor * map,int len,unsigned long * pix)1764 fli_find_closest_color( int             r,
1765                         int             g,
1766                         int             b,
1767                         XColor        * map,
1768                         int             len,
1769                         unsigned long * pix )
1770 {
1771     long mindiff = 0x7fffffffL,
1772          diff;
1773     int dr,
1774         dg,
1775         db;
1776     int i,
1777         k;
1778 
1779     for ( k = i = 0; i < len; i++ )
1780     {
1781         dr = r - ( ( map[ i ].red   >> 8 ) & 0xff );
1782         dg = g - ( ( map[ i ].green >> 8 ) & 0xff );
1783         db = b - ( ( map[ i ].blue  >> 8 ) & 0xff );
1784 
1785         /* Correct formula is (.299,.587,.114) */
1786 
1787 #if LINEAR_COLOR_DISTANCE
1788         diff = 3 * FL_abs( dr ) + 4 * FL_abs( dg ) + 2 * FL_abs( db );
1789 #else
1790         diff = 3 * ( dr * dr ) + 4 * ( dg * dg ) + 2 * ( db * db );
1791 #endif
1792 
1793         if ( diff < 0 )
1794             fprintf( stderr, "dr = %d dg = %d db = %d diff = %ld\n",
1795                      dr, dg, db, diff );
1796 
1797         if ( diff < mindiff )
1798         {
1799             mindiff = diff;
1800             k = i;
1801             *pix = map[ i ].pixel;
1802         }
1803     }
1804 
1805     return k;
1806 }
1807 
1808 
1809 /*
1810  * Local variables:
1811  * tab-width: 4
1812  * indent-tabs-mode: nil
1813  * End:
1814  */
1815