1 /* -*-c-*- */
2 /* Copyright (C) 1993, Robert Nation
3 * Copyright (C) 2002 Olivier Chapuis */
4 /* This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see: <http://www.gnu.org/licenses/>
16 */
17
18 /* ---------------------------- included header files ---------------------- */
19
20 #include "config.h"
21
22 #include <stdio.h>
23 #include <signal.h>
24 #include <ctype.h>
25 #include <math.h>
26
27 #include <X11/Xlib.h>
28 #include <X11/Xmd.h>
29
30 #include "fvwmlib.h"
31 #include "envvar.h"
32 #include "Grab.h"
33 #include "Parse.h"
34 #include "ftime.h"
35 #include "PictureBase.h"
36 #include "PictureUtils.h"
37 #include "PictureDitherMatrice.h"
38
39 /* ---------------------------- local definitions and macro ----------------- */
40
41 #if 0
42 /* dv: unused */
43 /* form alloc_in_cmap from the xpm lib */
44 #define XPM_DIST(r1,g1,b1,r2,g2,b2) (long)\
45 (3*(abs((long)r1-(long)r2) + \
46 abs((long)g1-(long)g2) + \
47 abs((long)b1-(long)b2)) + \
48 abs((long)r1 + (long)g1 + (long)b1 - \
49 ((long)r2 + (long)g2 + (long)b2)))
50 #define XPM_COLOR_CLOSENESS 40000
51 #endif
52
53 #define SQUARE(X) ((X)*(X))
54
55 #define TRUE_DIST(r1,g1,b1,r2,g2,b2) (long)\
56 (SQUARE((long)((r1 - r2)>>8)) \
57 + SQUARE((long)((g1 - g2)>>8)) \
58 + SQUARE((long)((b1 - b2)>>8)))
59
60 #define FAST_DIST(r1,g1,b1,r2,g2,b2) (long)\
61 (abs((long)(r1 - r2)) \
62 + abs((long)(g1 - g2)) \
63 + abs((long)(b1 - b2)))
64
65 #define FVWM_DIST(r1,g1,b1,r2,g2,b2) \
66 (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) \
67 + 2*abs(abs(r1-g1) + abs(g1-b1) + abs(r1-b1) \
68 - abs(r2-g2) - abs(g2-b2) - abs(r2-b2)))
69
70 #define USED_DIST(r1,g1,b1,r2,g2,b2) FVWM_DIST(r1,g1,b1,r2,g2,b2)
71
72 #define PICTURE_COLOR_CLOSENESS USED_DIST(3,3,3,0,0,0)
73
74 #define PICTURE_PAllocTable 1000000
75 #define PICTURE_PUseDynamicColors 100000
76 #define PICTURE_PStrictColorLimit 10000
77 #define PICTURE_use_named 1000
78 #define PICTURE_TABLETYPE_LENGHT 7
79
80 /* humm ... dither is probably borken with gamma correction. Anyway I do
81 * do think that using gamma correction for the colors cubes is a good
82 * idea */
83 #define USE_GAMMA_CORECTION 0
84 /* 2.2 is recommanded by the Poynon colors FAQ, some others suggest 1.5 and 2
85 * Use float constants!*/
86 #define COLOR_GAMMA 1.5
87 #define GREY_GAMMA 2.0
88
89 /* ---------------------------- imports ------------------------------------ */
90
91 /* ---------------------------- included code files ------------------------ */
92
93 /* ---------------------------- local types -------------------------------- */
94
95 typedef struct
96 {
97 XColor color; /* rgb color info */
98 unsigned long alloc_count; /* nbr of allocation */
99 } PColor;
100
101 typedef struct
102 {
103 /*
104 * info for colors table (depth <= 8)
105 */
106 /* color cube used */
107 short nr;
108 short ng;
109 short nb;
110 short ngrey;
111 /* grey palette def, nbr of grey = 2^grey_bits */
112 short grey_bits;
113 /* color cube used for dithering with the named table */
114 short d_nr;
115 short d_ng;
116 short d_nb;
117 short d_ngrey_bits;
118 /* do we found a pre-allocated pallet ? */
119 Bool pre_allocated_pallet;
120 /* info for depth > 8 */
121 int red_shift;
122 int green_shift;
123 int blue_shift;
124 int red_prec;
125 int green_prec;
126 int blue_prec;
127 /* for dithering in depth 15 and 16 */
128 unsigned short *red_dither;
129 unsigned short *green_dither;
130 unsigned short *blue_dither;
131 /* colors allocation function */
132 int (*alloc_color)(Display *dpy, Colormap cmap, XColor *c);
133 int (*alloc_color_no_limit)(Display *dpy, Colormap cmap, XColor *c);
134 int (*alloc_color_dither)(
135 Display *dpy, Colormap cmap, XColor *c, int x, int y);
136 void (*free_colors)(
137 Display *dpy, Colormap cmap, Pixel *pixels, int n,
138 unsigned long planes);
139 void (*free_colors_no_limit)(
140 Display *dpy, Colormap cmap, Pixel *pixels, int n,
141 unsigned long planes);
142 } PColorsInfo;
143
144 typedef struct {
145 int cols_index;
146 long closeness;
147 } CloseColor;
148
149 /* ---------------------------- forward declarations ----------------------- */
150
151 /* ---------------------------- local variables ---------------------------- */
152
153 static int PColorLimit = 0;
154 static PColor *Pct = NULL;
155 static PColor *Pac = NULL;
156 static short *PMappingTable = NULL;
157 static short *PDitherMappingTable = NULL;
158 static Bool PStrictColorLimit = 0;
159 static Bool PAllocTable = 0;
160 static PColorsInfo Pcsi = {
161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL,
162 NULL, NULL, NULL, NULL};
163
164 /* ---------------------------- exported variables (globals) --------------- */
165
166 /* ---------------------------- local functions ---------------------------- */
167
168 /*
169 * get shift and prec from a mask
170 */
171 static
decompose_mask(unsigned long mask,int * shift,int * prec)172 void decompose_mask(
173 unsigned long mask, int *shift, int *prec)
174 {
175 *shift = 0;
176 *prec = 0;
177
178 while (!(mask & 0x1))
179 {
180 (*shift)++;
181 mask >>= 1;
182 }
183
184 while (mask & 0x1)
185 {
186 (*prec)++;
187 mask >>= 1;
188 }
189 }
190
191 /*
192 * color allocation in the colormap. strongly inspired by SetCloseColor from
193 * the Xpm library (depth <= 8)
194 */
195
196 static int
closeness_cmp(const void * a,const void * b)197 closeness_cmp(const void *a, const void *b)
198 {
199 CloseColor *x = (CloseColor *) a, *y = (CloseColor *) b;
200
201 /* cast to int as qsort requires */
202 return (int) (x->closeness - y->closeness);
203 }
204
205 static
alloc_color_in_cmap(XColor * c,Bool force)206 int alloc_color_in_cmap(XColor *c, Bool force)
207 {
208 static XColor colors[256];
209 CloseColor closenesses[256];
210 XColor tmp;
211 int i,j;
212 int map_entries = (Pvisual->class == DirectColor)?
213 (1 << Pdepth) : Pvisual->map_entries;
214 time_t current_time;
215 time_t last_time = 0;
216
217 map_entries = (map_entries > 256)? 256:map_entries;
218 current_time = time(NULL);
219 if (current_time - last_time >= 2 || force)
220 {
221 last_time = current_time;
222 for (i = 0; i < map_entries; i++)
223 {
224 colors[i].pixel = i;
225 }
226 XQueryColors(Pdpy, Pcmap, colors, map_entries);
227 }
228 for(i = 0; i < map_entries; i++)
229 {
230 closenesses[i].cols_index = i;
231 closenesses[i].closeness = USED_DIST(
232 (int)(c->red),
233 (int)(c->green),
234 (int)(c->blue),
235 (int)(colors[i].red),
236 (int)(colors[i].green),
237 (int)(colors[i].blue));
238 }
239 qsort(closenesses, map_entries, sizeof(CloseColor), closeness_cmp);
240
241 i = 0;
242 j = closenesses[i].cols_index;
243 while (force ||
244 (abs((long)c->red - (long)colors[j].red) <=
245 PICTURE_COLOR_CLOSENESS &&
246 abs((long)c->green - (long)colors[j].green) <=
247 PICTURE_COLOR_CLOSENESS &&
248 abs((long)c->blue - (long)colors[j].blue) <=
249 PICTURE_COLOR_CLOSENESS))
250 {
251 tmp.red = colors[j].red;
252 tmp.green = colors[j].green;
253 tmp.blue = colors[j].blue;
254 if (XAllocColor(Pdpy, Pcmap, &tmp))
255 {
256 c->red = tmp.red;
257 c->green = tmp.green;
258 c->blue = tmp.blue;
259 c->pixel = tmp.pixel;
260 return 1;
261 }
262 else
263 {
264 i++;
265 if (i == map_entries)
266 break;
267 j = closenesses[i].cols_index;
268 }
269 }
270 return 0;
271 }
272
273 /*
274 * dithering
275 */
276
277 static
my_dither(int x,int y,XColor * c)278 int my_dither(int x, int y, XColor *c)
279 {
280 /* the dither matrice */
281 static const char DM[128][128] = DITHER_MATRICE;
282 int index;
283 const char *dmp;
284
285 if (Pcsi.grey_bits != 0)
286 {
287 /* Grey Scale */
288 int prec = Pcsi.grey_bits;
289
290 if (Pcsi.grey_bits == 1)
291 {
292 /* FIXME, can we do a better dithering */
293 prec = 2;
294 }
295 dmp = DM[(0 + y) & (DM_HEIGHT - 1)];
296 index = (c->green + ((c->blue + c->red) >> 1)) >> 1;
297 index += (dmp[(0 + x) & (DM_WIDTH - 1)] << 2) >> prec;
298 index = (index - (index >> prec));
299 index = index >> (8 - Pcsi.grey_bits);
300 }
301 else
302 {
303 /* color cube */
304 int dith, rs, gs, bs, gb, b;
305 int tr,tb,tg;
306
307 rs = Pcsi.d_nr - 1;
308 gs = Pcsi.d_ng - 1;
309 bs = Pcsi.d_nb - 1;
310 gb = Pcsi.d_ng*Pcsi.d_nb;
311 b = Pcsi.d_nb;
312
313 dmp = DM[(0 + y) & (DM_HEIGHT - 1)];
314 dith = (dmp[(0 + x) & (DM_WIDTH - 1)] << 2) | 7;
315 tr = ((c->red * rs) + dith) >> 8;
316 tg = ((c->green * gs) + (262 - dith)) >> 8;
317 tb = ((c->blue * bs) + dith) >> 8;
318 index = tr * gb + tg * b + tb;
319 #if 0
320 /* try to use the additonal grey. Not easy, good for
321 * certain image/gradient bad for others */
322 if (Pcsi.d_ngrey_bits)
323 {
324 int g_index;
325
326 /* dither in the Pcsi.ngrey^3 cc */
327 tr = ((c->red * (Pcsi.ngrey-1)) + dith) >> 8;
328 tg = ((c->green * (Pcsi.ngrey-1)) + (262 - dith)) >> 8;
329 tb = ((c->blue * (Pcsi.ngrey-1)) + dith) >> 8;
330 /* get the grey */
331 fprintf(stderr, "%i,%i,%i(%i/%i) ", tr,tg,tb,
332 abs(tr-tg) + abs(tb-tg) + abs(tb-tr),Pcsi.ngrey);
333 g_index = ((tr + tg + tb)/3);
334 if (g_index != 0 && g_index != Pcsi.ngrey-1 &&
335 abs(tr-tg) + abs(tb-tg) + abs(tb-tr) <=
336 Pcsi.d_ngrey_bits)
337 {
338 g_index = g_index + Pcsi.ng*Pcsi.nb*Pcsi.ng -1;
339 index = g_index;
340 }
341 }
342 #endif
343 if (PDitherMappingTable != NULL)
344 {
345 index = PDitherMappingTable[index];
346 }
347 }
348 return index;
349 }
350
351 static
my_dither_depth_15_16_init(void)352 int my_dither_depth_15_16_init(void)
353 {
354 const unsigned char _dither_44[4][4] =
355 {
356 {0, 4, 1, 5},
357 {6, 2, 7, 3},
358 {1, 5, 0, 4},
359 {7, 3, 6, 2}
360 };
361 int y,x,i;
362 int rm = 0xf8, re = 0x7, gm = 0xfc, ge = 0x3, bm = 0xf8, be = 0x7;
363
364 if (Pdepth == 16 && (Pvisual->red_mask == 0xf800) &&
365 (Pvisual->green_mask == 0x7e0) &&
366 (Pvisual->blue_mask == 0x1f))
367 {
368 /* ok */
369 }
370 else if (Pdepth == 15 && (Pvisual->red_mask == 0x7c00) &&
371 (Pvisual->green_mask == 0x3e0) &&
372 (Pvisual->blue_mask == 0x1f))
373 {
374 gm = 0xf8; ge = 0x7;
375 }
376 else
377 {
378 return 0; /* fail */
379 }
380
381 Pcsi.red_dither =
382 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
383 Pcsi.green_dither =
384 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
385 Pcsi.blue_dither =
386 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
387
388 for (y = 0; y < 4; y++)
389 {
390 for (x = 0; x < 4; x++)
391 {
392 for (i = 0; i < 256; i++)
393 {
394 if ((_dither_44[x][y] < (i & re)) &&
395 (i < (256 - 8)))
396 {
397 Pcsi.red_dither[
398 (x << 10) | (y << 8) | i] =
399 ((i + 8) & rm) << 8;
400 }
401 else
402 {
403 Pcsi.red_dither[
404 (x << 10) | (y << 8) | i] =
405 (i & rm) << 8;
406 }
407 if ((_dither_44[x][y] < ((i & ge) << 1))
408 && (i < (256 - 4)))
409 {
410 Pcsi.green_dither[
411 (x << 10) | (y << 8) | i] =
412 ((i + 4) & gm) << 8;
413 }
414 else
415 {
416 Pcsi.green_dither[
417 (x << 10) | (y << 8) | i] =
418 (i & gm) << 8;
419 }
420 if ((_dither_44[x][y] < (i & be)) &&
421 (i < (256 - 8)))
422 {
423 Pcsi.blue_dither[
424 (x << 10) | (y << 8) | i] =
425 ((i + 8) & bm) << 8;
426 }
427 else
428 {
429 Pcsi.blue_dither[
430 (x << 10) | (y << 8) | i] =
431 (i & bm) << 8;
432 }
433 }
434 }
435 }
436 return 1;
437 }
438
439 /*
440 * Color allocation in the "palette"
441 */
442
443 static
alloc_color_in_pct(XColor * c,int index)444 int alloc_color_in_pct(XColor *c, int index)
445 {
446 if (Pct[index].alloc_count == 0)
447 {
448 int s = PStrictColorLimit;
449
450 PStrictColorLimit = 0;
451 c->red = Pct[index].color.red;
452 c->green = Pct[index].color.green;
453 c->blue = Pct[index].color.blue;
454 PictureAllocColor(Pdpy, Pcmap, c, True); /* WARN (rec) */
455 Pct[index].color.pixel = c->pixel;
456 Pct[index].alloc_count = 1;
457 PStrictColorLimit = s;
458 }
459 else
460 {
461 c->red = Pct[index].color.red;
462 c->green = Pct[index].color.green;
463 c->blue = Pct[index].color.blue;
464 c->pixel = Pct[index].color.pixel;
465 if (Pct[index].alloc_count < 0xffffffff)
466 (Pct[index].alloc_count)++;
467 }
468 return 1;
469 }
470
471 static
get_color_index(int r,int g,int b,int is_8)472 int get_color_index(int r, int g, int b, int is_8)
473 {
474 int index;
475
476 if (!is_8)
477 {
478 r= r >> 8;
479 g= g >> 8;
480 b= b >> 8;
481 }
482 if (Pcsi.grey_bits > 0)
483 {
484 /* FIXME: Use other proporition ? */
485 index = ((r+g+b)/3) >> (8 - Pcsi.grey_bits);
486 }
487 else
488 {
489 #if 1
490 /* "exact" computation (corrected linear dist) */
491 float fr,fg,fb;
492 int ir, ig, ib;
493
494 /* map to the cube */
495 fr = ((float)r * (Pcsi.nr-1))/255;
496 fg = ((float)g * (Pcsi.ng-1))/255;
497 fb = ((float)b * (Pcsi.nb-1))/255;
498
499 if (PMappingTable != NULL)
500 {
501 ir = (int)fr + (fr - (int)fr > 0.5);
502 ig = (int)fg + (fg - (int)fg > 0.5);
503 ib = (int)fb + (fb - (int)fb > 0.5);
504
505 index = ir * Pcsi.ng*Pcsi.nb + ig * Pcsi.nb + ib;
506 }
507 else
508 {
509 /* found the best of the 8 linear closest points */
510 int lr,lg,lb,tr,tg,tb,best_dist = -1,i,d;
511
512 index = 0;
513 lr = min((int)fr+1,Pcsi.nr-1);
514 lg = min((int)fg+1,Pcsi.ng-1);
515 lb = min((int)fb+1,Pcsi.nb-1);
516 for(tr =(int)fr; tr<=lr; tr++)
517 {
518 for(tg =(int)fg; tg<=lg; tg++)
519 {
520 for(tb =(int)fb; tb<=lb; tb++)
521 {
522 i = tr * Pcsi.ng*Pcsi.nb +
523 tg * Pcsi.nb +
524 tb;
525 d = USED_DIST(
526 r,g,b,
527 (Pct[i].color.red>>8),
528 (Pct[i].color.green>>8),
529 (Pct[i].color.blue>>8));
530 if (best_dist == -1 ||
531 d < best_dist)
532 {
533 index = i;
534 best_dist = d;
535 }
536 }
537 }
538 }
539
540 /* now found the best grey */
541 if (Pcsi.ngrey - 2 > 0)
542 {
543 /* FIXME: speedup this with more than 8 grey */
544 int start = Pcsi.nr*Pcsi.ng*Pcsi.nb;
545 for(i=start; i < start+Pcsi.ngrey-2; i++)
546 {
547 d = USED_DIST(
548 r,g,b,
549 (Pct[i].color.red>>8),
550 (Pct[i].color.green>>8),
551 (Pct[i].color.blue>>8));
552 if (d < best_dist)
553 {
554 index = i;
555 best_dist = d;
556 }
557 }
558 }
559 return index;
560 }
561 #else
562 /* approximation; faster */
563 index = ((r * Pcsi.nr)>>8) * Pcsi.ng*Pcsi.nb +
564 ((g * Pcsi.ng)>>8) * Pcsi.nb +
565 ((b * Pcsi.nb)>>8);
566 #endif
567 if (PMappingTable != NULL)
568 {
569 index = PMappingTable[index];
570 }
571 }
572 return index;
573 }
574
575 /*
576 * Main colors allocator
577 */
578 static
alloc_color_proportion(Display * dpy,Colormap cmap,XColor * c)579 int alloc_color_proportion(Display *dpy, Colormap cmap, XColor *c)
580 {
581 c->pixel = (Pixel)(
582 ((c->red >> (16 - Pcsi.red_prec))<< Pcsi.red_shift) +
583 ((c->green >> (16 - Pcsi.green_prec))<< Pcsi.green_shift) +
584 ((c->blue >> (16 - Pcsi.blue_prec))<< Pcsi.blue_shift)
585 );
586 return 1;
587 }
588
589 static
alloc_color_proportion_dither(Display * dpy,Colormap cmap,XColor * c,int x,int y)590 int alloc_color_proportion_dither(
591 Display *dpy, Colormap cmap, XColor *c, int x, int y)
592 {
593 /* 8 bit colors !! */
594 c->red = Pcsi.red_dither[
595 (((x + 0) & 0x3) << 10) | ((y & 0x3) << 8) |
596 ((c->red) & 0xff)] * 257;
597 c->green = Pcsi.green_dither[
598 (((x + 0) & 0x3) << 10) | ((y & 0x3) << 8) |
599 ((c->green) & 0xff)] * 257;
600 c->blue = Pcsi.blue_dither[
601 (((x + 0) & 0x3) << 10) | ((y & 0x3) << 8) |
602 ((c->blue) & 0xff)] * 257;
603 c->pixel = (Pixel)(
604 ((c->red >> (16 - Pcsi.red_prec)) << Pcsi.red_shift) +
605 ((c->green >> (16 - Pcsi.green_prec))
606 << Pcsi.green_shift) +
607 ((c->blue >> (16 - Pcsi.blue_prec)) << Pcsi.blue_shift)
608 );
609 return 1;
610 }
611
612 static
alloc_color_proportion_grey(Display * dpy,Colormap cmap,XColor * c)613 int alloc_color_proportion_grey(
614 Display *dpy, Colormap cmap, XColor *c)
615 {
616 /* FIXME: is this ok in general? */
617 c->pixel = ((c->red + c->green + c->blue)/3);
618 if (Pdepth < 16)
619 {
620 c->pixel = c->pixel >> (16 - Pdepth);
621 }
622 return 1;
623 }
624
625 static
alloc_color_in_table(Display * dpy,Colormap cmap,XColor * c)626 int alloc_color_in_table(Display *dpy, Colormap cmap, XColor *c)
627 {
628
629 int index = get_color_index(c->red,c->green,c->blue, False);
630 return alloc_color_in_pct(c, index);
631 }
632
633 static
alloc_color_in_table_dither(Display * dpy,Colormap cmap,XColor * c,int x,int y)634 int alloc_color_in_table_dither(
635 Display *dpy, Colormap cmap, XColor *c, int x, int y)
636 {
637 int index;
638 /* 8 bit colors !! */
639 index = my_dither(x, y, c);
640 return alloc_color_in_pct(c, index);
641 }
642
643 static
alloc_color_dynamic_no_limit(Display * dpy,Colormap cmap,XColor * c)644 int alloc_color_dynamic_no_limit(
645 Display *dpy, Colormap cmap, XColor *c)
646 {
647 int r = 0;
648
649 if (XAllocColor(dpy, cmap, c))
650 {
651 r = 1;
652 }
653 else if (!alloc_color_in_cmap(c, False))
654 {
655 MyXGrabServer(dpy);
656 r = alloc_color_in_cmap(c, True);
657 MyXUngrabServer(dpy);
658 }
659 else
660 {
661 r = 1;
662 }
663 if (r && Pac != NULL && (c->pixel <= (1 << Pdepth) /* always true*/))
664 {
665 Pac[c->pixel].alloc_count++;
666 Pac[c->pixel].color.red = c->red;
667 Pac[c->pixel].color.green = c->green;
668 Pac[c->pixel].color.blue = c->blue;
669 Pac[c->pixel].color.pixel = c->pixel;
670 }
671 return r;
672 }
673
674 static
alloc_color_x(Display * dpy,Colormap cmap,XColor * c)675 int alloc_color_x(
676 Display *dpy, Colormap cmap, XColor *c)
677 {
678 return XAllocColor(dpy, cmap, c);
679 }
680
681 static
free_colors_in_table(Display * dpy,Colormap cmap,Pixel * pixels,int n,unsigned long planes)682 void free_colors_in_table(
683 Display *dpy, Colormap cmap, Pixel *pixels, int n,
684 unsigned long planes)
685 {
686 Pixel *p;
687 int i,j,do_free;
688 int m = 0;
689
690 if (!Pct || !PUseDynamicColors)
691 {
692 return;
693 }
694
695 p = (Pixel *)safemalloc(n*sizeof(Pixel));
696 for(i= 0; i < n; i++)
697 {
698 do_free = 1;
699 for(j=0; j<PColorLimit; j++)
700 {
701 if (Pct[j].alloc_count &&
702 Pct[j].alloc_count < 0xffffffff &&
703 pixels[i] == Pct[j].color.pixel)
704 {
705 (Pct[j].alloc_count)--;
706 if (Pct[j].alloc_count)
707 do_free = 0;
708 break;
709 }
710 }
711 if (do_free)
712 {
713 p[m++] = pixels[i];
714 }
715 }
716 if (m > 0)
717 {
718 XFreeColors(dpy, cmap, p, m, planes);
719 }
720 free(p);
721
722 return;
723 }
724
725 static
free_colors_x(Display * dpy,Colormap cmap,Pixel * pixels,int n,unsigned long planes)726 void free_colors_x(
727 Display *dpy, Colormap cmap, Pixel *pixels, int n,
728 unsigned long planes)
729 {
730 XFreeColors(dpy, cmap, pixels, n, planes);
731 if (Pac != NULL)
732 {
733 int nbr_colors = (1 << Pdepth);
734 int i;
735
736 for(i= 0; i < n; i++)
737 {
738 if (pixels[i] <= nbr_colors)
739 {
740 Pac[pixels[i]].alloc_count--;
741 }
742 }
743 }
744 }
745
746 /*
747 * local function for building pallet (dynamic colors, private DirectColor
748 * cmap)
749 */
750 static
build_mapping_colors(int nr,int ng,int nb)751 XColor *build_mapping_colors(int nr, int ng, int nb)
752 {
753 int r, g, b, i;
754 XColor *colors;
755
756 colors = (XColor *)safemalloc(nr*ng*nb * sizeof(XColor));
757 i = 0;
758 for (r = 0; r < nr; r++)
759 {
760 for (g = 0; g < ng; g++)
761 {
762 for (b = 0; b < nb; b++)
763 {
764 colors[i].red =
765 r * 65535 / (nr - 1);
766 colors[i].green =
767 g * 65535 / (ng - 1);
768 colors[i].blue =
769 b * 65535 / (nb - 1);
770 i++;
771 }
772 }
773 }
774 return colors;
775 }
776
build_mapping_table(int nr,int ng,int nb,Bool use_named)777 static short *build_mapping_table(int nr, int ng, int nb, Bool use_named)
778 {
779 int size = nr*ng*nb;
780 XColor *colors_map;
781 short *Table;
782 int i,j, minind;
783 double mindst = 40000;
784 double dst;
785
786 colors_map = build_mapping_colors(nr, ng, nb);
787 Table = (short *)safemalloc((size+1) * sizeof(short));
788 for(i=0; i<size; i++)
789 {
790 minind = 0;
791 for(j=0; j<PColorLimit; j++)
792 {
793 if (use_named)
794 {
795 /* for back ward compatibility */
796 dst = TRUE_DIST(colors_map[i].red,
797 colors_map[i].green,
798 colors_map[i].blue,
799 Pct[j].color.red,
800 Pct[j].color.green,
801 Pct[j].color.blue);
802 }
803 else
804 {
805 dst = USED_DIST(colors_map[i].red,
806 colors_map[i].green,
807 colors_map[i].blue,
808 Pct[j].color.red,
809 Pct[j].color.green,
810 Pct[j].color.blue);
811 }
812 if (j == 0 || dst < mindst)
813 {
814 mindst=dst;
815 minind=j;
816 }
817 }
818 Table[i] = minind;
819 }
820 Table[size] = Table[size-1];
821 free(colors_map);
822 return Table;
823 }
824
825 static
free_table_colors(PColor * color_table,int npixels)826 void free_table_colors(PColor *color_table, int npixels)
827 {
828 Pixel pixels[256];
829 int i,n=0;
830
831 if (npixels > 0)
832 {
833 for(i = 0; i < npixels; i++)
834 {
835 if (color_table[i].alloc_count)
836 {
837 pixels[n++] = color_table[i].color.pixel;
838 }
839 color_table[i].alloc_count = 0;
840 }
841 if (n > 0)
842 {
843 XFreeColors(Pdpy, Pcmap, pixels, n, 0);
844 }
845 }
846 }
847
848 /* FIXME: the DirectColor case */
849 static
get_nbr_of_free_colors(int max_check)850 int get_nbr_of_free_colors(int max_check)
851 {
852 int check = 1;
853 Pixel Pixels[256];
854 int map_entries = (Pvisual->class == DirectColor)?
855 (1 << Pdepth):Pvisual->map_entries;
856 if (max_check < 1)
857 return 0;
858 if (map_entries > 256)
859 {
860 max_check = 256;
861 }
862 max_check = (max_check > map_entries) ? map_entries:max_check;
863 while(1)
864 {
865 if (XAllocColorCells(
866 Pdpy, Pcmap, False, NULL, 0, Pixels, check))
867 {
868 XFreeColors(Pdpy, Pcmap, Pixels, check, 0);
869 check++;
870 }
871 else
872 {
873 return check-1;
874 }
875 if (check > max_check)
876 {
877 return check-1;
878 }
879 }
880 return check-1;
881 }
882
883 static
alloc_color_cube(int nr,int ng,int nb,int ngrey,int grey_bits,Bool do_allocate)884 PColor *alloc_color_cube(
885 int nr, int ng, int nb, int ngrey, int grey_bits, Bool do_allocate)
886 {
887 int r, g, b, grey, i, start_grey, end_grey;
888 PColor *color_table;
889 XColor color;
890 int size;
891
892 size = nr*ng*nb + ngrey + (1 << grey_bits)*(grey_bits != 0);
893 if (grey_bits)
894 {
895 ngrey = (1 << grey_bits);
896 }
897 if (nr > 0 && ngrey > 0)
898 {
899 start_grey = 1;
900 end_grey = ngrey - 1;
901 size = size - 2;
902 }
903 else
904 {
905 start_grey = 0;
906 end_grey = ngrey;
907 }
908
909 color_table = (PColor *)safemalloc((size+1) * sizeof(PColor));
910
911 i = 0;
912
913 #if USE_GAMMA_CORECTION
914 #define CG(x) 65535.0 * pow((x)/65535.0,1/COLOR_GAMMA)
915 #define GG(x) 65535.0 * pow((x)/65535.0,1/GREY_GAMMA)
916 #else
917 #define CG(x) x
918 #define GG(x) x
919 #endif
920
921 if (nr > 0)
922 {
923 for (r = 0; r < nr; r++)
924 {
925 for (g = 0; g < ng; g++)
926 {
927 for (b = 0; b < nb; b++)
928 {
929 color.red = CG(r * 65535 / (nr - 1));
930 color.green = CG(g * 65535 / (ng - 1));
931 color.blue = CG(b * 65535 / (nb - 1));
932 if (do_allocate)
933 {
934 if (!XAllocColor(Pdpy, Pcmap,
935 &color))
936 {
937 free_table_colors(
938 color_table, i);
939 free(color_table);
940 return NULL;
941 }
942 color_table[i].color.pixel =
943 color.pixel;
944 color_table[i].alloc_count = 1;
945 }
946 else
947 {
948 color_table[i].alloc_count = 0;
949 }
950 color_table[i].color.red = color.red;
951 color_table[i].color.green = color.green;
952 color_table[i].color.blue = color.blue;
953 i++;
954 }
955 }
956 }
957 }
958
959 if (ngrey > 0)
960 {
961 for (grey = start_grey; grey < end_grey; grey++)
962 {
963 color.red = color.green = color.blue =
964 GG(grey * 65535 / (ngrey - 1));
965 if (do_allocate)
966 {
967 if (!XAllocColor(Pdpy, Pcmap, &color))
968 {
969 free_table_colors(color_table, i);
970 free(color_table);
971 return NULL;
972 }
973 color_table[i].color.pixel = color.pixel;
974 color_table[i].alloc_count = 1;
975 }
976 else
977 {
978 color_table[i].alloc_count = 0;
979 }
980 color_table[i].color.red = color.red;
981 color_table[i].color.green = color.green;
982 color_table[i].color.blue = color.blue;
983 i++;
984 }
985 }
986 color_table[size].color.red = color_table[size-1].color.red;
987 color_table[size].color.green = color_table[size-1].color.green;
988 color_table[size].color.blue = color_table[size-1].color.blue;
989 color_table[size].color.pixel = color_table[size-1].color.pixel;
990 color_table[size].alloc_count = 0;
991 PColorLimit = size;
992 return color_table;
993 }
994
995
996 static
alloc_named_ct(int * limit,Bool do_allocate)997 PColor *alloc_named_ct(int *limit, Bool do_allocate)
998 {
999
1000 /* First thing in base array are colors probably already in the color map
1001 because they have familiar names.
1002 I pasted them into a xpm and spread them out so that similar colors are
1003 spread out.
1004 Toward the end are some colors to fill in the gaps.
1005 Currently 61 colors in this list.
1006 */
1007 char *color_names[] =
1008 {
1009 "black",
1010 "white",
1011 "grey",
1012 "green",
1013 "blue",
1014 "red",
1015 "cyan",
1016 "yellow",
1017 "magenta",
1018 "DodgerBlue",
1019 "SteelBlue",
1020 "chartreuse",
1021 "wheat",
1022 "turquoise",
1023 "CadetBlue",
1024 "gray87",
1025 "CornflowerBlue",
1026 "YellowGreen",
1027 "NavyBlue",
1028 "MediumBlue",
1029 "plum",
1030 "aquamarine",
1031 "orchid",
1032 "ForestGreen",
1033 "lightyellow",
1034 "brown",
1035 "orange",
1036 "red3",
1037 "HotPink",
1038 "LightBlue",
1039 "gray47",
1040 "pink",
1041 "red4",
1042 "violet",
1043 "purple",
1044 "gray63",
1045 "gray94",
1046 "plum1",
1047 "PeachPuff",
1048 "maroon",
1049 "lavender",
1050 "salmon", /* for peachpuff, orange gap */
1051 "blue4", /* for navyblue/mediumblue gap */
1052 "PaleGreen4", /* for forestgreen, yellowgreen gap */
1053 "#AA7700", /* brick, no close named color */
1054 "#11EE88", /* light green, no close named color */
1055 "#884466", /* dark brown, no close named color */
1056 "#CC8888", /* light brick, no close named color */
1057 "#EECC44", /* gold, no close named color */
1058 "#AAAA44", /* dull green, no close named color */
1059 "#FF1188", /* pinkish red */
1060 "#992299", /* purple */
1061 "#CCFFAA", /* light green */
1062 "#664400", /* dark brown*/
1063 "#AADD99", /* light green */
1064 "#66CCFF", /* light blue */
1065 "#CC2299", /* dark red */
1066 "#FF11CC", /* bright pink */
1067 "#11CC99", /* grey/green */
1068 "#AA77AA", /* purple/red */
1069 "#EEBB77" /* orange/yellow */
1070 };
1071 int NColors = sizeof(color_names)/sizeof(char *);
1072 int i,rc;
1073 PColor *color_table;
1074 XColor color;
1075
1076 *limit = (*limit > NColors)? NColors: *limit;
1077 color_table = (PColor *)safemalloc((*limit+1) * sizeof(PColor));
1078 for(i=0; i<*limit; i++)
1079 {
1080 rc=XParseColor(Pdpy, Pcmap, color_names[i], &color);
1081 if (rc==0) {
1082 fprintf(stderr,"color_to_rgb: can't parse color %s,"
1083 " rc %d\n", color_names[i], rc);
1084 free_table_colors(color_table, i);
1085 free(color_table);
1086 return NULL;
1087 }
1088 if (do_allocate)
1089 {
1090 if (!XAllocColor(Pdpy, Pcmap, &color))
1091 {
1092 free_table_colors(color_table, i);
1093 free(color_table);
1094 return NULL;
1095 }
1096 color_table[i].color.pixel = color.pixel;
1097 color_table[i].alloc_count = 1;
1098 }
1099 else
1100 {
1101 color_table[i].alloc_count = 0;
1102 }
1103 color_table[i].color.red = color.red;
1104 color_table[i].color.green = color.green;
1105 color_table[i].color.blue = color.blue;
1106 }
1107 color_table[*limit].color.red = color_table[*limit-1].color.red;
1108 color_table[*limit].color.green = color_table[*limit-1].color.green;
1109 color_table[*limit].color.blue = color_table[*limit-1].color.blue;
1110 color_table[*limit].color.pixel = color_table[*limit-1].color.pixel;
1111 color_table[*limit].alloc_count = 0;
1112 PColorLimit = *limit;
1113 return color_table;
1114 }
1115
1116 static
create_mapping_table(int nr,int ng,int nb,int ngrey,int grey_bits,Bool non_regular_pallet)1117 void create_mapping_table(
1118 int nr, int ng, int nb, int ngrey, int grey_bits,
1119 Bool non_regular_pallet)
1120 {
1121
1122 Pcsi.grey_bits = 0;
1123
1124 /* initialize dithering colors numbers */
1125 if (!non_regular_pallet)
1126 {
1127 /* */
1128 Pcsi.d_nr = nr;
1129 Pcsi.d_ng = ng;
1130 Pcsi.d_nb = nb;
1131 Pcsi.d_ngrey_bits = 2;
1132 while((1<<Pcsi.d_ngrey_bits) < ngrey)
1133 {
1134 Pcsi.d_ngrey_bits++;
1135 }
1136 if (1<<Pcsi.d_ngrey_bits != ngrey)
1137 {
1138 Pcsi.d_ngrey_bits = 0;
1139 }
1140 Pcsi.grey_bits = grey_bits;
1141 }
1142 else
1143 {
1144 /* dither table should be small */
1145 Pcsi.grey_bits = 0;
1146 if (PColorLimit <= 9)
1147 {
1148 Pcsi.d_nr = 3;
1149 Pcsi.d_ng = 3;
1150 Pcsi.d_nb = 3;
1151 Pcsi.d_ngrey_bits = 0;
1152 }
1153 else if (PColorLimit <= 64)
1154 {
1155 Pcsi.d_nr = 4;
1156 Pcsi.d_ng = 4;
1157 Pcsi.d_nb = 4;
1158 Pcsi.d_ngrey_bits = 0;
1159 }
1160 else
1161 {
1162 Pcsi.d_nr = 8;
1163 Pcsi.d_ng = 8;
1164 Pcsi.d_nb = 8;
1165 Pcsi.d_ngrey_bits = 0;
1166 }
1167 PDitherMappingTable = build_mapping_table(
1168 Pcsi.d_nr, Pcsi.d_ng, Pcsi.d_nb, non_regular_pallet);
1169 }
1170
1171 /* initialize colors number fo index computation */
1172 if (PColorLimit == 2)
1173 {
1174 /* ok */
1175 Pcsi.nr = 0;
1176 Pcsi.ng = 0;
1177 Pcsi.nb = 0;
1178 Pcsi.ngrey = 0;
1179 Pcsi.grey_bits = 1;
1180 }
1181 else if (grey_bits > 0)
1182 {
1183 Pcsi.nr = 0;
1184 Pcsi.ng = 0;
1185 Pcsi.nb = 0;
1186 Pcsi.ngrey = 0;
1187 Pcsi.grey_bits = grey_bits;
1188 }
1189 else if (non_regular_pallet || (0&&ngrey>0))
1190 {
1191 /* note: using these table with !used_named && ngrey>0 will
1192 * probably leads to faster image loading. But I see nothing
1193 * of significative. On the others hands not using it gives
1194 * maybe better colors approximation. */
1195 if (PColorLimit <= 9)
1196 {
1197 Pcsi.nr = 8;
1198 Pcsi.ng = 8;
1199 Pcsi.nb = 8;
1200 Pcsi.ngrey = 0;
1201 }
1202 else
1203 {
1204 Pcsi.nr = 16;
1205 Pcsi.ng = 16;
1206 Pcsi.nb = 16;
1207 Pcsi.ngrey = 0;
1208 }
1209 PMappingTable = build_mapping_table(
1210 Pcsi.nr, Pcsi.ng, Pcsi.nb, non_regular_pallet);
1211 }
1212 else
1213 {
1214 Pcsi.nr = nr;
1215 Pcsi.ng = ng;
1216 Pcsi.nb = nb;
1217 Pcsi.ngrey = ngrey;
1218 Pcsi.grey_bits = 0;
1219 }
1220 }
1221
finish_ct_init(int call_type,int ctt,int nr,int ng,int nb,int ngrey,int grey_bits,Bool use_named)1222 static void finish_ct_init(
1223 int call_type, int ctt, int nr, int ng, int nb, int ngrey,
1224 int grey_bits, Bool use_named)
1225 {
1226 if (call_type == PICTURE_CALLED_BY_FVWM)
1227 {
1228 char *env;
1229
1230 if (PAllocTable)
1231 {
1232 ctt = PICTURE_PAllocTable + ctt;
1233 }
1234 if (PUseDynamicColors)
1235 {
1236 ctt = PICTURE_PUseDynamicColors + ctt;
1237 }
1238 if (PStrictColorLimit)
1239 {
1240 ctt = PICTURE_PStrictColorLimit + ctt;
1241 }
1242 if (use_named)
1243 {
1244 ctt = PICTURE_use_named + ctt;
1245 }
1246 else
1247 {
1248 ctt++;
1249 }
1250 env = safemalloc(PICTURE_TABLETYPE_LENGHT + 1);
1251 sprintf(env, "%i", ctt);
1252 flib_putenv("FVWM_COLORTABLE_TYPE", env);
1253 free(env);
1254 if (Pdepth <= 8)
1255 {
1256 Pac = (PColor *)safecalloc(
1257 (1 << Pdepth), sizeof(PColor));
1258 }
1259 }
1260
1261 if (Pct)
1262 {
1263 if (!PAllocTable && call_type == PICTURE_CALLED_BY_FVWM)
1264 {
1265 free_table_colors(Pct, PColorLimit);
1266 }
1267 create_mapping_table(nr,ng,nb,ngrey,grey_bits,use_named);
1268 }
1269 }
1270
1271 #define PA_COLOR_CUBE (1 << 1)
1272 #define FVWM_COLOR_CUBE (1 << 2)
1273 #define PA_GRAY_SCALE (1 << 3)
1274 #define FVWM_GRAY_SCALE (1 << 4)
1275 #define ANY_COLOR_CUBE (PA_COLOR_CUBE|FVWM_COLOR_CUBE)
1276 #define ANY_GRAY_SCALE (PA_GRAY_SCALE|FVWM_GRAY_SCALE)
1277
1278 static
PictureAllocColorTable(PictureColorLimitOption * opt,int call_type,Bool use_my_color_limit)1279 int PictureAllocColorTable(
1280 PictureColorLimitOption *opt, int call_type, Bool use_my_color_limit)
1281 {
1282 char *envp;
1283 int free_colors, nbr_of_color, limit, cc_nbr, i, size;
1284 int use_named_table = 0;
1285 int do_allocate = 0;
1286 int use_default = 1;
1287 int private_cmap = !(Pdefault);
1288 int color_limit;
1289 int pa_type = (Pvisual->class != GrayScale) ?
1290 PA_COLOR_CUBE : PA_GRAY_SCALE;
1291 int fvwm_type = (Pvisual->class != GrayScale) ?
1292 FVWM_COLOR_CUBE : FVWM_GRAY_SCALE;
1293 int cc[][6] =
1294 {
1295 /* {nr,ng,nb,ngrey,grey_bits,logic} */
1296 /* 5 first for direct colors and Pdepth > 8*/
1297 /* 8192 colors depth 13, a reasonable max for a color table */
1298 {16, 32, 16, 0, 0, FVWM_COLOR_CUBE},
1299 /* 4096 colors depth 12 */
1300 {16, 16, 16, 0, 0, FVWM_COLOR_CUBE},
1301 /* 1024 colors depth 10 */
1302 {8, 16, 8, 0, 0, FVWM_COLOR_CUBE},
1303 /* 512 colors depth 9 */
1304 {8, 8, 8, 0, 0, FVWM_COLOR_CUBE},
1305 /* 256 colors 3/3/2 standard colormap */
1306 {8, 8, 4, 0, 0, FVWM_COLOR_CUBE},
1307 /* 256 grey scale */
1308 {0, 0, 0, 0, 8, ANY_GRAY_SCALE},
1309 /* 244 Xrender XFree-4.2 */
1310 {6, 6, 6, 30, 0, ANY_COLOR_CUBE},
1311 /* 216 Xrender XFree-4.2,GTK/QT "default cc" */
1312 {6, 6, 6, 0, 0, ANY_COLOR_CUBE},
1313 /* 180 (GTK) */
1314 {6, 6, 5, 0, 0, ANY_COLOR_CUBE},
1315 /* 144 (GTK) */
1316 {6, 6, 4, 0, 0, ANY_COLOR_CUBE},
1317 /* 128 grey scale */
1318 {0, 0, 0, 0, 7, ANY_GRAY_SCALE},
1319 /* 125 GTK mini default cc (may change? 444) */
1320 {5, 5, 5, 0, 0, ANY_COLOR_CUBE},
1321 /* 100 (GTK with color limit) */
1322 {5, 5, 4, 0, 0, ANY_COLOR_CUBE},
1323 /* 85 Xrender XFree-4.3 */
1324 {4, 4, 4, 23, 0, ANY_COLOR_CUBE},
1325 /* 78 (in fact 76) a good default ??*/
1326 {4, 4, 4, 16, 0, FVWM_COLOR_CUBE},
1327 /* 70 a good default ?? */
1328 {4, 4, 4, 8, 0, ANY_COLOR_CUBE},
1329 /* 68 a good default ?? */
1330 {4, 4, 4, 6, 0, ANY_COLOR_CUBE},
1331 /* 64 Xrender XFree-4.3 (GTK wcl) */
1332 {4, 4, 4, 0, 0, ANY_COLOR_CUBE},
1333 /* 64 grey scale */
1334 {0, 0, 0, 0, 6, ANY_GRAY_SCALE},
1335 /* 54, maybe a good default? */
1336 {4, 4, 3, 8, 0, FVWM_COLOR_CUBE},
1337 /* 48, (GTK wcl) no grey but ok */
1338 {4, 4, 3, 0, 0, FVWM_COLOR_CUBE},
1339 /* 32, 2/2/1 standard colormap */
1340 {4, 4, 2, 0, 0, FVWM_COLOR_CUBE},
1341 /* 32 xrender xfree-4.2 */
1342 {0, 0, 0, 0, 6, ANY_GRAY_SCALE},
1343 /* 29 */
1344 {3, 3, 3, 4, 0, FVWM_COLOR_CUBE},
1345 /* 27 (xrender in depth 6&7(hypo) GTK wcl) */
1346 {3, 3, 3, 0, 0, FVWM_COLOR_CUBE|PA_COLOR_CUBE*(Pdepth<8)},
1347 /* 16 grey scale */
1348 {0, 0, 0, 0, 4, FVWM_GRAY_SCALE},
1349 /* 10 */
1350 {2, 2, 2, 4, 0, FVWM_COLOR_CUBE},
1351 /* 8 (xrender/qt/gtk wcl) */
1352 {2, 2, 2, 0, 0, FVWM_COLOR_CUBE},
1353 /* 8 grey scale Xrender depth 4 and XFree-4.3 */
1354 {0, 0, 0, 0, 3, FVWM_GRAY_SCALE|PA_GRAY_SCALE*(Pdepth<5)},
1355 /* 4 grey scale*/
1356 {0, 0, 0, 0, 2,
1357 FVWM_GRAY_SCALE|FVWM_COLOR_CUBE|PA_COLOR_CUBE*(Pdepth<4)},
1358 /* 2 */
1359 {0, 0, 0, 0, 1, FVWM_COLOR_CUBE|FVWM_GRAY_SCALE}
1360 };
1361
1362 cc_nbr = sizeof(cc)/(sizeof(cc[0]));
1363
1364 /* set up default */
1365 PStrictColorLimit = 0;
1366 PUseDynamicColors = 1;
1367 PAllocTable = 0;
1368 use_named_table = False;
1369 color_limit = 0;
1370 use_default = True;
1371
1372 /* use fvwm color limit */
1373 if (!use_my_color_limit &&
1374 (envp = getenv("FVWM_COLORTABLE_TYPE")) != NULL)
1375 {
1376 int nr = 0, ng = 0, nb = 0, grey_bits = 0, ngrey = 0;
1377 int ctt = atoi(envp);
1378
1379 if (ctt >= PICTURE_PAllocTable)
1380 {
1381 ctt -= PICTURE_PAllocTable;
1382 PAllocTable = 1; /* not useful for a module !*/
1383 }
1384 if (ctt >= PICTURE_PUseDynamicColors)
1385 {
1386 PUseDynamicColors = 1;
1387 ctt -= PICTURE_PUseDynamicColors;
1388 }
1389 if (ctt >= PICTURE_PStrictColorLimit)
1390 {
1391 PStrictColorLimit = 1;
1392 ctt -= PICTURE_PStrictColorLimit;
1393 }
1394 if (ctt >= PICTURE_use_named)
1395 {
1396 ctt -= PICTURE_use_named;
1397 Pct = alloc_named_ct(&ctt, False);
1398 use_named_table = True;
1399 }
1400 else if (ctt == 0)
1401 {
1402 /* depth <= 8 and no colors limit ! */
1403 PColorLimit = 0;
1404 return 0;
1405 }
1406 else if (ctt <= cc_nbr)
1407 {
1408 ctt--;
1409 Pct = alloc_color_cube(
1410 cc[ctt][0], cc[ctt][1], cc[ctt][2], cc[ctt][3],
1411 cc[ctt][4],
1412 False);
1413 nr = cc[ctt][0];
1414 ng = cc[ctt][1];
1415 nb = cc[ctt][2];
1416 ngrey = cc[ctt][3];
1417 grey_bits = cc[ctt][4];
1418 }
1419 if (Pct != NULL)
1420 {
1421 /* should always happen */
1422 finish_ct_init(
1423 call_type, ctt, nr, ng, nb, ngrey, grey_bits,
1424 use_named_table);
1425 return PColorLimit;
1426 }
1427 }
1428
1429 nbr_of_color = (1 << Pdepth);
1430 color_limit = 0;
1431
1432 /* parse the color limit env variable */
1433 if ((envp = getenv("FVWM_COLORLIMIT")) != NULL)
1434 {
1435 char *rest, *l;
1436
1437 rest = GetQuotedString(envp, &l, ":", NULL, NULL, NULL);
1438 if (l && *l != '\0' && (color_limit = atoi(l)) >= 0)
1439 {
1440 use_default = 0;
1441 }
1442 if (l != NULL)
1443 {
1444 free(l);
1445 }
1446 if (color_limit == 9 || color_limit == 61)
1447 {
1448 use_named_table = 1;
1449 }
1450 if (rest && *rest != '\0')
1451 {
1452 if (rest[0] == '1')
1453 {
1454 PStrictColorLimit = 1;
1455 }
1456 else
1457 {
1458 PStrictColorLimit = 0;
1459 }
1460 if (strlen(rest) > 1 && rest[1] == '1')
1461 {
1462 use_named_table = 1;
1463 }
1464 else
1465 {
1466 use_named_table = 0;
1467 }
1468 if (strlen(rest) > 2 && rest[2] == '1')
1469 {
1470 PUseDynamicColors = 1;
1471 }
1472 else
1473 {
1474 PUseDynamicColors = 0;
1475 }
1476 if (strlen(rest) > 3 && rest[3] == '1')
1477 {
1478 PAllocTable = 1;
1479 }
1480 else
1481 {
1482 PAllocTable = 0;
1483 }
1484 }
1485 }
1486 else if (opt != NULL) /* use the option */
1487 {
1488 if (opt->color_limit > 0)
1489 {
1490 use_default = 0;
1491 color_limit = opt->color_limit;
1492 }
1493 if (color_limit == 9 || color_limit == 61)
1494 {
1495 use_named_table = 1;
1496 }
1497 if (opt->strict > 0)
1498 {
1499 PStrictColorLimit = 1;
1500 }
1501 else if (opt->strict == 0)
1502 {
1503 PStrictColorLimit = 0;
1504 }
1505 if (opt->use_named_table > 0)
1506 {
1507 use_named_table = 1;
1508 }
1509 else if (opt->use_named_table == 0)
1510 {
1511 use_named_table = 0;
1512 }
1513 if (opt->not_dynamic > 0)
1514 {
1515 PUseDynamicColors = 0;
1516 }
1517 else if (opt->not_dynamic == 0)
1518 {
1519 PUseDynamicColors = 0;
1520 }
1521 if (opt->allocate > 0)
1522 {
1523 PAllocTable = 1;
1524 }
1525 else if (opt->allocate == 0)
1526 {
1527 PAllocTable = 0;
1528 }
1529 }
1530
1531 if (color_limit <= 0)
1532 {
1533 use_default = 1;
1534 color_limit = nbr_of_color;
1535 }
1536
1537 /* first try to see if we have a "pre-allocated" color cube.
1538 * The bultin RENDER X extension pre-allocate a color cube plus
1539 * some grey's (xc/programs/Xserver/render/miindex)
1540 * See gdk/gdkrgb.c for the cubes used by gtk+-2, 666 is the default,
1541 * 555 is the minimal cc (this may change): if gtk cannot allocate
1542 * the 555 cc (or better) a private cmap is used.
1543 * for qt-3: see src/kernel/{qapplication.cpp,qimage.cpp,qcolor_x11.c}
1544 * the 666 cube is used by default (with approx in the cmap if some
1545 * color allocation fail), and some qt app may accept an
1546 * --ncols option to limit the nbr of colors, then some "2:3:1"
1547 * proportions color cube are used (222, 232, ..., 252, 342, ..., 362,
1548 * 452, ...,693, ...)
1549 * imlib2 try to allocate the 666 cube if this fail it try more
1550 * exotic table (see rend.c and rgba.c) */
1551 i = 0;
1552 free_colors = 0;
1553 if (Pdepth <= 8 && !private_cmap && use_default &&
1554 i < cc_nbr && Pct == NULL && (Pvisual->class & 1))
1555 {
1556 free_colors = get_nbr_of_free_colors(nbr_of_color);
1557 }
1558 while(Pdepth <= 8 && !private_cmap && use_default &&
1559 i < cc_nbr && Pct == NULL && (Pvisual->class & 1))
1560 {
1561 size = cc[i][0]*cc[i][1]*cc[i][2] + cc[i][3] -
1562 2*(cc[i][3] > 0) + (1 << cc[i][4])*(cc[i][4] != 0);
1563 if (size > nbr_of_color || !(cc[i][5] & pa_type))
1564 {
1565 i++;
1566 continue;
1567 }
1568 if (free_colors <= nbr_of_color - size)
1569 {
1570 Pct = alloc_color_cube(
1571 cc[i][0], cc[i][1], cc[i][2], cc[i][3],
1572 cc[i][4], True);
1573 }
1574 if (Pct != NULL)
1575 {
1576 if (free_colors <=
1577 get_nbr_of_free_colors(nbr_of_color))
1578 {
1579 /* done */
1580 }
1581 else
1582 {
1583 free_table_colors(Pct, PColorLimit);
1584 free(Pct);
1585 Pct = NULL;
1586 }
1587 }
1588 i++;
1589 }
1590 if (Pct != NULL)
1591 {
1592 PUseDynamicColors = 0;
1593 PAllocTable = 1;
1594 Pcsi.pre_allocated_pallet = 1;
1595 i = i - 1;
1596 finish_ct_init(
1597 call_type, i, cc[i][0], cc[i][1], cc[i][2], cc[i][3],
1598 cc[i][4], 0);
1599 return PColorLimit;
1600 }
1601
1602 /*
1603 * now use "our" table
1604 */
1605
1606 limit = (color_limit >= nbr_of_color)? nbr_of_color:color_limit;
1607
1608 if (use_default && !private_cmap)
1609 {
1610 /* XRender cvs default: */
1611 #if 0
1612 if (limit > 100)
1613 limit = nbr_of_color/3;
1614 else
1615 limit = nbr_of_color/2;
1616 /* depth 8: 85 */
1617 /* depth 4: 8 */
1618 #endif
1619 if (limit > 256)
1620 {
1621 /* direct colors & Pdepth > 8 */
1622 if (Pdepth >= 16)
1623 {
1624 limit = 8192;
1625 }
1626 else if (Pdepth >= 15)
1627 {
1628 limit = 4096;
1629 }
1630 else
1631 {
1632 limit = 512;
1633 }
1634 }
1635 else if (limit == 256)
1636 {
1637 if (Pvisual->class == GrayScale)
1638 {
1639 limit = 64;
1640 }
1641 else if (Pvisual->class == DirectColor)
1642 {
1643 limit = 32;
1644 }
1645 else
1646 {
1647 limit = 68;
1648 /* candidate:
1649 * limit = 54; 4x4x3 + 6 grey
1650 * limit = 61 (named table)
1651 * limit = 85 current XRender default 4cc + 21
1652 * limit = 76 future(?) XRender default 4cc + 16
1653 * limit = 68 4x4x4 + 4
1654 * limit = 64 4x4x4 + 0 */
1655 }
1656
1657 }
1658 else if (limit == 128 || limit == 64)
1659 {
1660 if (Pvisual->class == GrayScale)
1661 {
1662 limit = 32;
1663 }
1664 else
1665 {
1666 limit = 31;
1667 }
1668 }
1669 else if (limit >= 16)
1670 {
1671 if (Pvisual->class == GrayScale)
1672 {
1673 limit = 8;
1674 }
1675 else
1676 {
1677 limit = 10;
1678 }
1679 }
1680 else if (limit >= 8)
1681 {
1682 limit = 4;
1683 }
1684 else
1685 {
1686 limit = 2;
1687 }
1688 }
1689 if (limit < 2)
1690 {
1691 limit = 2;
1692 }
1693
1694 if (Pvisual->class == DirectColor)
1695 {
1696 /* humm ... Any way this case should never happen in real life:
1697 * DirectColor default colormap! */
1698 PUseDynamicColors = 0;
1699 PAllocTable = 1;
1700 PStrictColorLimit = 1;
1701 }
1702 if (PAllocTable)
1703 {
1704 do_allocate = 1;
1705 }
1706 else
1707 {
1708 do_allocate = 0;
1709 }
1710
1711 /* use the named table ? */
1712 if (use_named_table)
1713 {
1714 i = limit;
1715 while(Pct == NULL && i >= 2)
1716 {
1717 Pct = alloc_named_ct(&i, do_allocate);
1718 i--;
1719 }
1720 }
1721 if (Pct != NULL)
1722 {
1723 finish_ct_init(
1724 call_type, PColorLimit, 0, 0, 0, 0, 0, 1);
1725 return PColorLimit;
1726 }
1727
1728 /* color cube or regular grey scale */
1729 i = 0;
1730 while(i < cc_nbr && Pct == NULL)
1731 {
1732 if ((cc[i][5] & fvwm_type) &&
1733 cc[i][0]*cc[i][1]*cc[i][2] + cc[i][3] - 2*(cc[i][3] > 0) +
1734 (1 << cc[i][4])*(cc[i][4] != 0) <= limit)
1735 {
1736 Pct = alloc_color_cube(
1737 cc[i][0], cc[i][1], cc[i][2], cc[i][3], cc[i][4],
1738 do_allocate);
1739 }
1740 i++;
1741 }
1742 if (Pct != NULL)
1743 {
1744 i = i-1;
1745 finish_ct_init(
1746 call_type, i, cc[i][0], cc[i][1], cc[i][2], cc[i][3],
1747 cc[i][4], 0);
1748 return PColorLimit;
1749 }
1750
1751 /* I do not think we can be here */
1752 Pct = alloc_color_cube(0, 0, 0, 0, 1, False);
1753 finish_ct_init(call_type, cc_nbr-1, 0, 0, 0, 0, 1, 0);
1754 if (Pct == NULL)
1755 {
1756 fprintf(stderr,
1757 "[fvwm] ERR -- Cannot get Black and White. exiting!\n");
1758 exit(2);
1759 }
1760 return PColorLimit;
1761 }
1762
1763 /*
1764 * Allocation of a private DirectColor cmap this is broken for depth > 16
1765 */
1766 static
alloc_direct_colors(int * limit,Bool use_my_color_limit)1767 Bool alloc_direct_colors(int *limit, Bool use_my_color_limit)
1768 {
1769 unsigned long nr,ng,nb,r,g,b,cr,cg,cf,pr,pg;
1770 unsigned long red_mask, green_mask, blue_mask;
1771 XColor *colors;
1772
1773 if (Pdepth <= 16)
1774 {
1775 red_mask = Pvisual->red_mask;
1776 green_mask = Pvisual->green_mask;
1777 blue_mask = Pvisual->blue_mask;
1778 }
1779 else
1780 {
1781 /* Use a standard depth 16 colormap. This is broken FIXME! */
1782 red_mask = 0xf800;
1783 green_mask = 0x7e0;
1784 blue_mask = 0x1f;
1785 }
1786
1787 decompose_mask(
1788 red_mask, &Pcsi.red_shift, &Pcsi.red_prec);
1789 decompose_mask(
1790 green_mask, &Pcsi.green_shift, &Pcsi.green_prec);
1791 decompose_mask(
1792 blue_mask, &Pcsi.blue_shift, &Pcsi.blue_prec);
1793
1794 if (!use_my_color_limit)
1795 {
1796 /* colors allocated by fvwm we can return */
1797 return 1;
1798 }
1799
1800 nr = 1 << Pcsi.red_prec;
1801 ng = 1 << Pcsi.green_prec;
1802 nb = 1 << Pcsi.blue_prec;
1803
1804 colors = (XColor *)safemalloc(nb*sizeof(XColor));
1805 cf = DoRed|DoBlue|DoGreen;
1806 for (r=0; r<nr; r++)
1807 {
1808 cr = r * 65535 / (nr - 1);
1809 pr = (cr >> (16 - Pcsi.red_prec)) << Pcsi.red_shift;
1810 for (g = 0; g < ng; g++)
1811 {
1812 cg = g * 65535 / (ng - 1);
1813 pg = (cg >> (16 - Pcsi.green_prec)) << Pcsi.green_shift;
1814 for (b = 0; b < nb; b++)
1815 {
1816 colors[b].flags = cf;
1817 colors[b].red = cr;
1818 colors[b].green = cg;
1819 colors[b].blue = b * 65535 / (nb - 1);
1820 colors[b].pixel =
1821 (Pixel)(pr + pg +
1822 ((colors[b].blue >>
1823 (16 - Pcsi.blue_prec)) <<
1824 Pcsi.blue_shift));
1825 }
1826 XStoreColors(Pdpy, Pcmap, colors, nb);
1827 }
1828 }
1829 free(colors);
1830 return 1;
1831 }
1832
1833 /*
1834 * Init the table for Static Colors
1835 */
1836 static
init_static_colors_table(void)1837 void init_static_colors_table(void)
1838 {
1839 XColor colors[256];
1840 int i;
1841 int nbr_of_colors = min(256, (1 << Pdepth));
1842
1843 PColorLimit = nbr_of_colors;
1844 Pct = (PColor *)safemalloc((nbr_of_colors+1) * sizeof(PColor));
1845 for (i = 0; i < nbr_of_colors; i++)
1846 {
1847 colors[i].pixel = Pct[i].color.pixel = i;
1848 }
1849 XQueryColors(Pdpy, Pcmap, colors, nbr_of_colors);
1850 for (i = 0; i < nbr_of_colors; i++)
1851 {
1852 Pct[i].color.red = colors[i].red;
1853 Pct[i].color.green = colors[i].green;
1854 Pct[i].color.blue = colors[i].blue;
1855 Pct[i].alloc_count = 1;
1856 }
1857 Pct[PColorLimit].color.red = Pct[PColorLimit-1].color.red;
1858 Pct[PColorLimit].color.green = Pct[PColorLimit-1].color.green;
1859 Pct[PColorLimit].color.blue = Pct[PColorLimit-1].color.blue;
1860 Pct[PColorLimit].alloc_count = 1;
1861 create_mapping_table(0, 0, 0, 0, 0, True);
1862 }
1863
1864
1865 /*
1866 * misc local functions
1867 */
1868 static
print_colormap(Colormap cmap)1869 void print_colormap(Colormap cmap)
1870 {
1871 XColor colors[256];
1872 int i;
1873 int nbr_of_colors = max(256, (1 << Pdepth));
1874 for (i = 0; i < nbr_of_colors; i++)
1875 {
1876 colors[i].pixel = i;
1877 }
1878 XQueryColors(Pdpy, cmap, colors, nbr_of_colors);
1879 for (i = 0; i < nbr_of_colors; i++)
1880 {
1881 fprintf(stderr," rgb(%.3i): %.3i/%.3i/%.3i\n", i,
1882 colors[i].red >> 8,
1883 colors[i].green >> 8,
1884 colors[i].blue >> 8);
1885 }
1886 }
1887
1888 /* ---------------------------- interface functions ------------------------ */
1889
PictureAllocColor(Display * dpy,Colormap cmap,XColor * c,int no_limit)1890 int PictureAllocColor(Display *dpy, Colormap cmap, XColor *c, int no_limit)
1891 {
1892 if (PStrictColorLimit && Pct != NULL)
1893 {
1894 no_limit = 0;
1895 }
1896
1897 if (no_limit)
1898 {
1899 return Pcsi.alloc_color_no_limit(dpy, cmap, c);
1900 }
1901 else
1902 {
1903 return Pcsi.alloc_color(dpy, cmap, c);
1904 }
1905 return 0;
1906 }
1907
1908
PictureAllocColorAllProp(Display * dpy,Colormap cmap,XColor * c,int x,int y,Bool no_limit,Bool is_8,Bool do_dither)1909 int PictureAllocColorAllProp(
1910 Display *dpy, Colormap cmap, XColor *c, int x, int y,
1911 Bool no_limit, Bool is_8, Bool do_dither)
1912 {
1913
1914 if (!no_limit && do_dither && Pcsi.alloc_color_dither != NULL)
1915 {
1916 if (!is_8)
1917 {
1918 c->red = c->red >> 8;
1919 c->green = c->green >> 8;
1920 c->blue = c->blue >> 8;
1921 }
1922 return Pcsi.alloc_color_dither(dpy, cmap, c, x, y);
1923 }
1924 else
1925 {
1926 if (is_8)
1927 {
1928 c->red = c->red << 8;
1929 c->green = c->green << 8;
1930 c->blue = c->blue << 8;
1931 }
1932 return PictureAllocColor(dpy, cmap, c, False);
1933 }
1934 return 0;
1935 }
1936
PictureAllocColorImage(Display * dpy,PictureImageColorAllocator * pica,XColor * c,int x,int y)1937 int PictureAllocColorImage(
1938 Display *dpy, PictureImageColorAllocator *pica, XColor *c, int x, int y)
1939 {
1940 int r;
1941
1942 r = PictureAllocColorAllProp(
1943 dpy, pica->cmap, c, x, y,
1944 pica->no_limit, pica->is_8, pica->dither);
1945 if (r && pica->pixels_table != NULL && pica->pixels_table_size &&
1946 c->pixel < pica->pixels_table_size)
1947 {
1948 pica->pixels_table[c->pixel]++;
1949 }
1950 return r;
1951 }
1952
PictureOpenImageColorAllocator(Display * dpy,Colormap cmap,int x,int y,Bool no_limit,Bool do_not_save_pixels,int dither,Bool is_8)1953 PictureImageColorAllocator *PictureOpenImageColorAllocator(
1954 Display *dpy, Colormap cmap, int x, int y, Bool no_limit,
1955 Bool do_not_save_pixels, int dither, Bool is_8)
1956 {
1957 PictureImageColorAllocator *pica;
1958 Bool do_save_pixels = False;
1959
1960 pica = (PictureImageColorAllocator *)safemalloc(
1961 sizeof(PictureImageColorAllocator));
1962 if (Pdepth <= 8 && !do_not_save_pixels && (Pvisual->class & 1) &&
1963 ((PUseDynamicColors && Pct) || no_limit))
1964 {
1965 int s = 1 << Pdepth;
1966 pica->pixels_table = (unsigned long *)safecalloc(
1967 s, sizeof(unsigned long));
1968 pica->pixels_table_size = s;
1969 do_save_pixels = True;
1970 }
1971 if (!do_save_pixels)
1972 {
1973 pica->pixels_table = NULL;
1974 pica->pixels_table_size = 0;
1975 }
1976 pica->is_8 = is_8;
1977 if (dither && Pdepth <= 16)
1978 {
1979 pica->dither = dither;
1980 }
1981 else
1982 {
1983 pica->dither = dither;
1984 }
1985 pica->no_limit = no_limit;
1986 pica->cmap = cmap;
1987 return pica;
1988 }
1989
PictureCloseImageColorAllocator(Display * dpy,PictureImageColorAllocator * pica,int * nalloc_pixels,Pixel ** alloc_pixels,Bool * no_limit)1990 void PictureCloseImageColorAllocator(
1991 Display *dpy, PictureImageColorAllocator *pica,
1992 int *nalloc_pixels, Pixel **alloc_pixels, Bool *no_limit)
1993 {
1994 if (nalloc_pixels)
1995 {
1996 *nalloc_pixels = 0;
1997 }
1998 if (alloc_pixels != NULL)
1999 {
2000 *alloc_pixels = NULL;
2001 }
2002 if (no_limit != NULL)
2003 {
2004 *no_limit = 0;
2005 }
2006 if (pica->pixels_table)
2007 {
2008 int i,j;
2009 int k = 0, l = 0;
2010 unsigned int np = 0;
2011 int free_num = 0;
2012 Pixel *free_pixels = NULL;
2013 Pixel *save_pixels = NULL;
2014
2015 for(i = 0; i < pica->pixels_table_size; i++)
2016 {
2017 if (pica->pixels_table[i])
2018 {
2019 free_num += (pica->pixels_table[i]-1);
2020 np++;
2021 }
2022 }
2023 if (free_num)
2024 {
2025 free_pixels = (Pixel *)safemalloc(
2026 free_num * sizeof(Pixel));
2027 }
2028 if (np && nalloc_pixels != NULL && alloc_pixels != NULL)
2029 {
2030 save_pixels = (Pixel *)safemalloc(np * sizeof(Pixel));
2031 }
2032 for(i = 0; i < pica->pixels_table_size; i++)
2033 {
2034 if (pica->pixels_table[i])
2035 {
2036 if (save_pixels)
2037 {
2038 save_pixels[k++] = i;
2039 }
2040 for(j=1; j < pica->pixels_table[i]; j++)
2041 {
2042 free_pixels[l++] = i;
2043 }
2044 }
2045 }
2046 if (free_num)
2047 {
2048 PictureFreeColors(
2049 dpy, pica->cmap, free_pixels, free_num, 0,
2050 pica->no_limit);
2051 free(free_pixels);
2052 }
2053 if (nalloc_pixels != NULL && alloc_pixels != NULL)
2054 {
2055 *nalloc_pixels = np;
2056 *alloc_pixels = save_pixels;
2057 if (no_limit != NULL)
2058 {
2059 *no_limit = pica->no_limit;
2060 }
2061 }
2062 else if (save_pixels)
2063 {
2064 free(save_pixels);
2065 }
2066 free(pica->pixels_table);
2067 }
2068 free(pica);
2069 return;
2070 }
2071
PictureFreeColors(Display * dpy,Colormap cmap,Pixel * pixels,int n,unsigned long planes,Bool no_limit)2072 void PictureFreeColors(
2073 Display *dpy, Colormap cmap, Pixel *pixels, int n,
2074 unsigned long planes, Bool no_limit)
2075 {
2076 if (no_limit)
2077 {
2078 if (Pcsi.free_colors_no_limit != NULL)
2079 {
2080 Pcsi.free_colors_no_limit(
2081 dpy, cmap, pixels, n, planes);
2082 }
2083 }
2084 else
2085 {
2086 if (Pcsi.free_colors != NULL)
2087 {
2088 Pcsi.free_colors(dpy, cmap, pixels, n, planes);
2089 }
2090 }
2091 return;
2092 }
2093
PictureGetNextColor(Pixel p,int n)2094 Pixel PictureGetNextColor(Pixel p, int n)
2095 {
2096 int i;
2097 XColor c;
2098
2099 if (n >= 0)
2100 n = 1;
2101 else
2102 n = -1;
2103
2104 if (Pct == NULL)
2105 {
2106 return p;
2107 }
2108 for(i=0; i<PColorLimit; i++)
2109 {
2110 if (Pct[i].color.pixel == p)
2111 {
2112 if (i == 0 && n < 0)
2113 {
2114 c = Pct[PColorLimit-1].color;
2115 alloc_color_in_pct(&c, PColorLimit-1);
2116 return Pct[PColorLimit-1].color.pixel;
2117 }
2118 else if (i == PColorLimit-1 && n > 0)
2119 {
2120 c = Pct[0].color;
2121 alloc_color_in_pct(&c, 0);
2122 return Pct[0].color.pixel;
2123 }
2124 else
2125 {
2126 c = Pct[i+n].color;
2127 alloc_color_in_pct(&c, i+n);
2128 return Pct[i+n].color.pixel;
2129 }
2130 }
2131 }
2132 return p;
2133 }
2134
2135 /* Replace the color in my_color by the closest matching color
2136 from base_table */
PictureReduceColorName(char ** my_color)2137 void PictureReduceColorName(char **my_color)
2138 {
2139 int index;
2140 XColor rgb; /* place to calc rgb for each color in xpm */
2141
2142 if (!XpmSupport)
2143 return;
2144
2145 if (!strcasecmp(*my_color,"none")) {
2146 return; /* do not substitute the "none" color */
2147 }
2148
2149 if (!XParseColor(Pdpy, Pcmap, *my_color, &rgb))
2150 {
2151 fprintf(stderr,"color_to_rgb: can't parse color %s\n",
2152 *my_color);
2153 }
2154 index = get_color_index(rgb.red,rgb.green,rgb.blue, False);
2155 /* Finally: replace the color string by the newly determined color
2156 * string */
2157 free(*my_color); /* free old color */
2158 /* area for new color */
2159 *my_color = safemalloc(8);
2160 sprintf(*my_color,"#%x%x%x",
2161 Pct[index].color.red >> 8,
2162 Pct[index].color.green >> 8,
2163 Pct[index].color.blue >> 8); /* put it there */
2164 return;
2165 }
2166
PictureDitherByDefault(void)2167 Bool PictureDitherByDefault(void)
2168 {
2169 if (Pct != NULL)
2170 {
2171 return True;
2172 }
2173 return False;
2174 }
2175
PictureUseBWOnly(void)2176 Bool PictureUseBWOnly(void)
2177 {
2178 if (Pdepth < 2 || (PStrictColorLimit && PColorLimit == 2))
2179 {
2180 return True;
2181 }
2182 return False;
2183 }
2184
PictureInitColors(int call_type,Bool init_color_limit,PictureColorLimitOption * opt,Bool use_my_color_limit,Bool init_dither)2185 int PictureInitColors(
2186 int call_type, Bool init_color_limit, PictureColorLimitOption *opt,
2187 Bool use_my_color_limit, Bool init_dither)
2188 {
2189 Bool dither_ok = False;
2190
2191 switch (Pvisual->class)
2192 {
2193 case DirectColor:
2194 /* direct colors is more or less broken */
2195 decompose_mask(
2196 Pvisual->red_mask, &Pcsi.red_shift,
2197 &Pcsi.red_prec);
2198 decompose_mask(
2199 Pvisual->green_mask, &Pcsi.green_shift,
2200 &Pcsi.green_prec);
2201 decompose_mask(
2202 Pvisual->blue_mask, &Pcsi.blue_shift,
2203 &Pcsi.blue_prec);
2204 Pcsi.alloc_color_no_limit = alloc_color_proportion;
2205 Pcsi.alloc_color = alloc_color_proportion;
2206 Pcsi.alloc_color_dither = alloc_color_proportion_dither;
2207 Pcsi.free_colors_no_limit = NULL;
2208 Pcsi.free_colors = NULL;
2209 PColorLimit = 0;
2210 break;
2211 case TrueColor:
2212 decompose_mask(
2213 Pvisual->red_mask, &Pcsi.red_shift,
2214 &Pcsi.red_prec);
2215 decompose_mask(
2216 Pvisual->green_mask, &Pcsi.green_shift,
2217 &Pcsi.green_prec);
2218 decompose_mask(
2219 Pvisual->blue_mask, &Pcsi.blue_shift,
2220 &Pcsi.blue_prec);
2221 Pcsi.alloc_color_no_limit = alloc_color_proportion;
2222 Pcsi.alloc_color = alloc_color_proportion;
2223 Pcsi.free_colors_no_limit = NULL;
2224 Pcsi.free_colors = NULL;
2225 PColorLimit = 0;
2226 if (init_dither && (Pdepth == 15 || Pdepth == 16))
2227 {
2228 dither_ok = my_dither_depth_15_16_init();
2229 }
2230 if (dither_ok)
2231 {
2232 Pcsi.alloc_color_dither = alloc_color_proportion_dither;
2233 }
2234 else
2235 {
2236 Pcsi.alloc_color_dither = NULL;
2237 }
2238 break;
2239 case StaticColor:
2240 if (0 && Pvisual->red_mask != 0 && Pvisual->green_mask != 0 &&
2241 Pvisual->blue_mask != 0)
2242 {
2243 decompose_mask(
2244 Pvisual->red_mask, &Pcsi.red_shift,
2245 &Pcsi.red_prec);
2246 decompose_mask(
2247 Pvisual->green_mask, &Pcsi.green_shift,
2248 &Pcsi.green_prec);
2249 decompose_mask(
2250 Pvisual->blue_mask, &Pcsi.blue_shift,
2251 &Pcsi.blue_prec);
2252 Pcsi.alloc_color_no_limit = alloc_color_proportion;
2253 Pcsi.alloc_color = alloc_color_proportion;
2254 PColorLimit = 0;
2255 }
2256 else
2257 {
2258 if (init_color_limit)
2259 {
2260 Pcsi.alloc_color = alloc_color_in_table;
2261 Pcsi.alloc_color_dither =
2262 alloc_color_in_table_dither;
2263 Pcsi.alloc_color_no_limit = alloc_color_x;
2264 init_static_colors_table();
2265 }
2266 else
2267 {
2268 Pcsi.alloc_color = alloc_color_x;
2269 Pcsi.alloc_color_dither = NULL;
2270 Pcsi.alloc_color_no_limit = alloc_color_x;
2271 }
2272 }
2273 Pcsi.free_colors_no_limit = NULL;
2274 Pcsi.free_colors = NULL;
2275 break;
2276 case StaticGray:
2277 /* FIXME: we assume that we have a regular grey ramp */
2278 if (0)
2279 {
2280 Pcsi.alloc_color_no_limit = alloc_color_proportion_grey;
2281 Pcsi.alloc_color = alloc_color_proportion;
2282 PColorLimit = 0;
2283 }
2284 else
2285 {
2286 if (init_color_limit)
2287 {
2288 Pcsi.alloc_color = alloc_color_in_table;
2289 Pcsi.alloc_color_dither =
2290 alloc_color_in_table_dither;
2291 Pcsi.alloc_color_no_limit = alloc_color_x;
2292 init_static_colors_table();
2293 }
2294 else
2295 {
2296 Pcsi.alloc_color = alloc_color_x;
2297 Pcsi.alloc_color_dither = NULL;
2298 Pcsi.alloc_color_no_limit = alloc_color_x;
2299 }
2300 }
2301 Pcsi.free_colors_no_limit = NULL;
2302 Pcsi.free_colors = NULL;
2303 break;
2304 case PseudoColor:
2305 case GrayScale:
2306 default:
2307 Pcsi.alloc_color_no_limit = alloc_color_dynamic_no_limit;
2308 Pcsi.free_colors_no_limit = free_colors_x;
2309 break;
2310 }
2311
2312 if (!(Pvisual->class & 1))
2313 {
2314 /* static classes */
2315 PUseDynamicColors = 0;
2316 if (call_type == PICTURE_CALLED_BY_FVWM &&
2317 getenv("FVWM_COLORTABLE_TYPE") != NULL)
2318 {
2319 flib_putenv("FVWM_COLORTABLE_TYPE", "");
2320 }
2321 return PColorLimit;
2322 }
2323
2324 /* dynamic classes */
2325
2326 if (!Pdefault && Pvisual->class == DirectColor)
2327 {
2328 PColorLimit = 0;
2329 PUseDynamicColors = 0;
2330 alloc_direct_colors(0, use_my_color_limit);
2331 if (call_type == PICTURE_CALLED_BY_FVWM &&
2332 getenv("FVWM_COLORTABLE_TYPE") != NULL)
2333 {
2334 flib_putenv("FVWM_COLORTABLE_TYPE", "");
2335 }
2336 return 0;
2337 }
2338
2339
2340 if (init_color_limit)
2341 {
2342 Pcsi.alloc_color = alloc_color_in_table;
2343 Pcsi.alloc_color_dither = alloc_color_in_table_dither;
2344 PictureAllocColorTable(opt, call_type, use_my_color_limit);
2345 if (PUseDynamicColors)
2346 {
2347 Pcsi.free_colors = free_colors_in_table;
2348 }
2349 else
2350 {
2351 Pcsi.free_colors = NULL;
2352 }
2353 }
2354 else
2355 {
2356 Pcsi.alloc_color = alloc_color_dynamic_no_limit;
2357 Pcsi.free_colors = free_colors_x;
2358 Pcsi.alloc_color_dither = NULL;
2359 }
2360 return PColorLimit;
2361 }
2362
PicturePrintColorInfo(int verbose)2363 void PicturePrintColorInfo(int verbose)
2364 {
2365 unsigned long nbr_of_colors = 1 << Pdepth;
2366
2367 fprintf(stderr, "fvwm info on colors\n");
2368 fprintf(stderr, " Visual ID: 0x%x, Default?: %s, Class: ",
2369 (int)(Pvisual->visualid),
2370 (Pdefault)? "Yes":"No");
2371 if (Pvisual->class == TrueColor)
2372 {
2373 fprintf(stderr,"TrueColor");
2374 }
2375 else if (Pvisual->class == PseudoColor)
2376 {
2377 fprintf(stderr,"PseudoColor");
2378 }
2379 else if (Pvisual->class == DirectColor)
2380 {
2381 fprintf(stderr,"DirectColor");
2382 }
2383 else if (Pvisual->class == StaticColor)
2384 {
2385 fprintf(stderr,"StaticColor");
2386 }
2387 else if (Pvisual->class == GrayScale)
2388 {
2389 fprintf(stderr,"GrayScale");
2390 }
2391 else if (Pvisual->class == StaticGray)
2392 {
2393 fprintf(stderr,"StaticGray");
2394 }
2395 fprintf(stderr, "\n");
2396 fprintf(stderr, " Depth: %i, Number of colors: %lu",
2397 Pdepth, (unsigned long)nbr_of_colors);
2398 if (Pct != NULL)
2399 {
2400 fprintf(stderr,"\n Pallet with %i colors", PColorLimit);
2401 if (Pvisual->class & 1)
2402 {
2403 fprintf(stderr,", Number of free colors: %i\n",
2404 get_nbr_of_free_colors((1 << Pdepth)));
2405 fprintf(stderr,
2406 " Auto Detected: %s, Strict: %s, Allocated: %s,"
2407 " Dynamic: %s\n",
2408 (Pcsi.pre_allocated_pallet)? "Yes":"No",
2409 (PStrictColorLimit)? "Yes":"No",
2410 (PAllocTable)? "Yes":"No",
2411 (PUseDynamicColors)? "Yes":"No");
2412 }
2413 else
2414 {
2415 fprintf(stderr," (default colormap)\n");
2416 }
2417 if (PColorLimit <= 256)
2418 {
2419 int i;
2420 int count = 0;
2421 int count_alloc = 0;
2422
2423 if (verbose)
2424 {
2425 fprintf(stderr," The fvwm colors table:\n");
2426 }
2427 for (i = 0; i < PColorLimit; i++)
2428 {
2429 if (verbose)
2430 {
2431 fprintf(
2432 stderr,
2433 " rgb:%.3i/%.3i/%.3i\t%lu\n",
2434 Pct[i].color.red >> 8,
2435 Pct[i].color.green >> 8,
2436 Pct[i].color.blue >> 8,
2437 Pct[i].alloc_count);
2438 }
2439 if (Pct[i].alloc_count)
2440 {
2441 count++;
2442 }
2443 }
2444 if ((Pvisual->class & 1) && Pac != NULL)
2445 {
2446 if (verbose)
2447 {
2448 fprintf(stderr," fvwm colors not in"
2449 " the table:\n");
2450 }
2451 for(i=0; i < nbr_of_colors; i++)
2452 {
2453 int j = 0;
2454 Bool found = False;
2455
2456 if (!Pac[i].alloc_count)
2457 continue;
2458 while(j < PColorLimit && !found)
2459 {
2460 if (i == Pct[j].color.pixel)
2461 {
2462 found = True;
2463 }
2464 j++;
2465 }
2466 if (found)
2467 continue;
2468 count_alloc++;
2469 if (verbose)
2470 {
2471 fprintf(
2472 stderr,
2473 " rgb:"
2474 "%.3i/%.3i/%.3i\t%lu\n",
2475 Pac[i].color.red >> 8,
2476 Pac[i].color.green >> 8,
2477 Pac[i].color.blue >> 8,
2478 Pac[i].alloc_count);
2479 }
2480 }
2481 if (verbose && count_alloc == 0)
2482 {
2483 if (verbose)
2484 {
2485 fprintf(stderr," None\n");
2486 }
2487 }
2488 }
2489 if (Pvisual->class & 1)
2490 {
2491 fprintf(stderr,
2492 " Number of colours used by fvwm:\n");
2493 fprintf(stderr,
2494 " In the table: %i\n", count);
2495 fprintf(
2496 stderr, " Out of the table: %i\n",
2497 count_alloc);
2498 fprintf(stderr,
2499 " Total: %i\n", count_alloc+count);
2500 }
2501 }
2502 }
2503 else
2504 {
2505 if (Pvisual->class == DirectColor)
2506 {
2507 fprintf(stderr, ", Pseudo Pallet with: %i colors\n",
2508 (1 << Pcsi.red_prec)*(1 << Pcsi.green_prec)*
2509 (1 << Pcsi.blue_prec));
2510 }
2511 else
2512 {
2513 fprintf(stderr, ", No Pallet (static colors)\n");
2514 }
2515 fprintf(stderr, " red: %i, green: %i, blue %i\n",
2516 1 << Pcsi.red_prec, 1 << Pcsi.green_prec,
2517 1 << Pcsi.blue_prec);
2518 if (verbose && Pdepth <= 8)
2519 {
2520 if (Pvisual->class == DirectColor)
2521 {
2522 fprintf(stderr, " Colormap:\n");
2523 }
2524 else
2525 {
2526 fprintf(stderr,
2527 " Static Colormap used by fvwm:\n");
2528 }
2529 print_colormap(Pcmap);
2530 }
2531 }
2532
2533 if (Pdepth <= 8 && verbose >= 2)
2534 {
2535 fprintf(stderr,"\n Default Colormap:\n");
2536 print_colormap(DefaultColormap(Pdpy,DefaultScreen(Pdpy)));
2537 }
2538 }
2539