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