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