2 /* Copyright (C) 1993, Robert Nation
3 * Copyright (C) 2002 Olivier Chapuis
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 /* ---------------------------- included header files ----------------------- */
35 #include "PictureBase.h"
36 #include "PictureUtils.h"
37 #include "PictureDitherMatrice.h"
39 /* ---------------------------- local definitions and macro ------------------ */
41 #define PICTURE_DEBUG_COLORS_ALLOC_FAILURE 0
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
52 #define SQUARE(X) ((X)*(X))
54 #define TRUE_DIST(r1,g1,b1,r2,g2,b2) (long)\
55 (SQUARE((long)((r1 - r2)>>8)) \
56 + SQUARE((long)((g1 - g2)>>8)) \
57 + SQUARE((long)((b1 - b2)>>8)))
59 #define FAST_DIST(r1,g1,b1,r2,g2,b2) (long)\
60 (abs((long)(r1 - r2)) \
61 + abs((long)(g1 - g2)) \
62 + abs((long)(b1 - b2)))
64 #define FVWM_DIST(r1,g1,b1,r2,g2,b2) \
65 (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) \
66 + 2*abs(abs(r1-g1) + abs(g1-b1) + abs(r1-b1) \
67 - abs(r2-g2) - abs(g2-b2) - abs(r2-b2)))
69 #define USED_DIST(r1,g1,b1,r2,g2,b2) FVWM_DIST(r1,g1,b1,r2,g2,b2)
71 #define PICTURE_COLOR_CLOSENESS USED_DIST(3,3,3,0,0,0)
73 #define PICTURE_PAllocTable 1000000
74 #define PICTURE_PUseDynamicColors 100000
75 #define PICTURE_PStrictColorLimit 10000
76 #define PICTURE_use_named 1000
77 #define PICTURE_TABLETYPE_LENGHT 7
79 /* humm ... dither is probably borken with gamma correction. Anyway I do
80 * do think that using gamma correction for the colors cubes is a good
82 #define USE_GAMMA_CORECTION 0
83 /* 2.2 is recommanded by the Poynon colors FAQ, some others suggest 1.5 and 2
84 * Use float constants!*/
85 #define COLOR_GAMMA 1.5
86 #define GREY_GAMMA 2.0
88 /* ---------------------------- imports ------------------------------------- */
90 /* ---------------------------- included code files ------------------------- */
92 /* ---------------------------- local types --------------------------------- */
96 XColor color
; /* rgb color info */
97 unsigned long alloc_count
; /* nbr of allocation */
103 * info for colors table (depth <= 8)
105 /* color cube used */
110 /* grey palette def, nbr of grey = 2^grey_bits */
112 /* color cube used for dithering with the named table */
117 /* do we found a pre-allocated pallet ? */
118 Bool pre_allocated_pallet
;
119 /* info for depth > 8 */
126 /* for dithering in depth 15 and 16 */
127 unsigned short *red_dither
;
128 unsigned short *green_dither
;
129 unsigned short *blue_dither
;
130 /* colors allocation function */
131 int (*alloc_color
)();
132 int (*alloc_color_no_limit
)();
133 int (*alloc_color_dither
)();
134 void (*free_colors
)();
135 void (*free_colors_no_limit
)();
143 /* ---------------------------- forward declarations ------------------------ */
145 /* ---------------------------- local variables ----------------------------- */
147 static int PColorLimit
= 0;
148 static PColor
*Pct
= NULL
;
149 static PColor
*Pac
= NULL
;
150 static short *PMappingTable
= NULL
;
151 static short *PDitherMappingTable
= NULL
;
152 static Bool PStrictColorLimit
= 0;
153 static Bool PAllocTable
= 0;
154 static PColorsInfo Pcsi
= {
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL
, NULL
, NULL
, NULL
,
156 NULL
, NULL
, NULL
, NULL
};
158 /* ---------------------------- exported variables (globals) ---------------- */
160 /* ---------------------------- local functions ----------------------------- */
162 /* ***************************************************************************
163 * get shift and prec from a mask
164 * ***************************************************************************/
167 unsigned long mask
, int *shift
, int *prec
)
172 while (!(mask
& 0x1))
185 /* ***************************************************************************
186 * color allocation in the colormap. strongly inspired by SetCloseColor from
187 * the Xpm library (depth <= 8)
188 * ***************************************************************************/
191 closeness_cmp(const void *a
, const void *b
)
193 CloseColor
*x
= (CloseColor
*) a
, *y
= (CloseColor
*) b
;
195 /* cast to int as qsort requires */
196 return (int) (x
->closeness
- y
->closeness
);
200 int alloc_color_in_cmap(XColor
*c
, Bool force
)
202 static XColor colors
[256];
203 CloseColor closenesses
[256];
206 int map_entries
= (Pvisual
->class == DirectColor
)?
207 (1 << Pdepth
) : Pvisual
->map_entries
;
209 time_t last_time
= 0;
211 map_entries
= (map_entries
> 256)? 256:map_entries
;
212 current_time
= time(NULL
);
213 if (current_time
- last_time
>= 2 || force
)
215 last_time
= current_time
;
216 for (i
= 0; i
< map_entries
; i
++)
220 XQueryColors(Pdpy
, Pcmap
, colors
, map_entries
);
222 for(i
= 0; i
< map_entries
; i
++)
224 closenesses
[i
].cols_index
= i
;
225 closenesses
[i
].closeness
= USED_DIST(
229 (int)(colors
[i
].red
),
230 (int)(colors
[i
].green
),
231 (int)(colors
[i
].blue
));
233 qsort(closenesses
, map_entries
, sizeof(CloseColor
), closeness_cmp
);
236 j
= closenesses
[i
].cols_index
;
238 (abs((long)c
->red
- (long)colors
[j
].red
) <=
239 PICTURE_COLOR_CLOSENESS
&&
240 abs((long)c
->green
- (long)colors
[j
].green
) <=
241 PICTURE_COLOR_CLOSENESS
&&
242 abs((long)c
->blue
- (long)colors
[j
].blue
) <=
243 PICTURE_COLOR_CLOSENESS
))
245 tmp
.red
= colors
[j
].red
;
246 tmp
.green
= colors
[j
].green
;
247 tmp
.blue
= colors
[j
].blue
;
248 if (XAllocColor(Pdpy
, Pcmap
, &tmp
))
251 c
->green
= tmp
.green
;
253 c
->pixel
= tmp
.pixel
;
259 if (i
== map_entries
)
261 j
= closenesses
[i
].cols_index
;
267 /* ***************************************************************************
269 * ***************************************************************************/
272 int my_dither(int x
, int y
, XColor
*c
)
274 /* the dither matrice */
275 static const char DM
[128][128] = DITHER_MATRICE
;
279 if (Pcsi
.grey_bits
!= 0)
282 int prec
= Pcsi
.grey_bits
;
284 if (Pcsi
.grey_bits
== 1)
286 /* FIXME, can we do a better dithering */
289 dmp
= DM
[(0 + y
) & (DM_HEIGHT
- 1)];
290 index
= (c
->green
+ ((c
->blue
+ c
->red
) >> 1)) >> 1;
291 index
+= (dmp
[(0 + x
) & (DM_WIDTH
- 1)] << 2) >> prec
;
292 index
= (index
- (index
>> prec
));
293 index
= index
>> (8 - Pcsi
.grey_bits
);
298 int dith
, rs
, gs
, bs
, gb
, b
;
304 gb
= Pcsi
.d_ng
*Pcsi
.d_nb
;
307 dmp
= DM
[(0 + y
) & (DM_HEIGHT
- 1)];
308 dith
= (dmp
[(0 + x
) & (DM_WIDTH
- 1)] << 2) | 7;
309 tr
= ((c
->red
* rs
) + dith
) >> 8;
310 tg
= ((c
->green
* gs
) + (262 - dith
)) >> 8;
311 tb
= ((c
->blue
* bs
) + dith
) >> 8;
312 index
= tr
* gb
+ tg
* b
+ tb
;
314 /* try to use the additonal grey. Not easy, good for
315 * certain image/gradient bad for others */
316 if (Pcsi
.d_ngrey_bits
)
320 /* dither in the Pcsi.ngrey^3 cc */
321 tr
= ((c
->red
* (Pcsi
.ngrey
-1)) + dith
) >> 8;
322 tg
= ((c
->green
* (Pcsi
.ngrey
-1)) + (262 - dith
)) >> 8;
323 tb
= ((c
->blue
* (Pcsi
.ngrey
-1)) + dith
) >> 8;
325 fprintf(stderr
, "%i,%i,%i(%i/%i) ", tr
,tg
,tb
,
326 abs(tr
-tg
) + abs(tb
-tg
) + abs(tb
-tr
),Pcsi
.ngrey
);
327 g_index
= ((tr
+ tg
+ tb
)/3);
328 if (g_index
!= 0 && g_index
!= Pcsi
.ngrey
-1 &&
329 abs(tr
-tg
) + abs(tb
-tg
) + abs(tb
-tr
) <=
332 g_index
= g_index
+ Pcsi
.ng
*Pcsi
.nb
*Pcsi
.ng
-1;
337 if (PDitherMappingTable
!= NULL
)
339 index
= PDitherMappingTable
[index
];
346 int my_dither_depth_15_16_init(void)
348 const unsigned char _dither_44
[4][4] =
356 int rm
= 0xf8, re
= 0x7, gm
= 0xfc, ge
= 0x3, bm
= 0xf8, be
= 0x7;
358 if (Pdepth
== 16 && (Pvisual
->red_mask
== 0xf800) &&
359 (Pvisual
->green_mask
== 0x7e0) &&
360 (Pvisual
->blue_mask
== 0x1f))
364 else if (Pdepth
== 15 && (Pvisual
->red_mask
== 0x7c00) &&
365 (Pvisual
->green_mask
== 0x3e0) &&
366 (Pvisual
->blue_mask
== 0x1f))
376 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
378 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
380 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
382 for (y
= 0; y
< 4; y
++)
384 for (x
= 0; x
< 4; x
++)
386 for (i
= 0; i
< 256; i
++)
388 if ((_dither_44
[x
][y
] < (i
& re
)) &&
392 (x
<< 10) | (y
<< 8) | i
] =
398 (x
<< 10) | (y
<< 8) | i
] =
401 if ((_dither_44
[x
][y
] < ((i
& ge
) << 1))
405 (x
<< 10) | (y
<< 8) | i
] =
411 (x
<< 10) | (y
<< 8) | i
] =
414 if ((_dither_44
[x
][y
] < (i
& be
)) &&
418 (x
<< 10) | (y
<< 8) | i
] =
424 (x
<< 10) | (y
<< 8) | i
] =
433 /* ***************************************************************************
434 * Color allocation in the "palette"
435 * ***************************************************************************/
438 int alloc_color_in_pct(XColor
*c
, int index
)
440 if (Pct
[index
].alloc_count
== 0)
442 int s
= PStrictColorLimit
;
444 PStrictColorLimit
= 0;
445 c
->red
= Pct
[index
].color
.red
;
446 c
->green
= Pct
[index
].color
.green
;
447 c
->blue
= Pct
[index
].color
.blue
;
448 PictureAllocColor(Pdpy
, Pcmap
, c
, True
); /* WARN (rec) */
449 Pct
[index
].color
.pixel
= c
->pixel
;
450 Pct
[index
].alloc_count
= 1;
451 PStrictColorLimit
= s
;
455 c
->red
= Pct
[index
].color
.red
;
456 c
->green
= Pct
[index
].color
.green
;
457 c
->blue
= Pct
[index
].color
.blue
;
458 c
->pixel
= Pct
[index
].color
.pixel
;
459 if (Pct
[index
].alloc_count
< 0xffffffff)
460 (Pct
[index
].alloc_count
)++;
466 int get_color_index(int r
, int g
, int b
, int is_8
)
476 if (Pcsi
.grey_bits
> 0)
478 /* FIXME: Use other proporition ? */
479 index
= ((r
+g
+b
)/3) >> (8 - Pcsi
.grey_bits
);
484 /* "exact" computation (corrected linear dist) */
488 /* map to the cube */
489 fr
= ((float)r
* (Pcsi
.nr
-1))/255;
490 fg
= ((float)g
* (Pcsi
.ng
-1))/255;
491 fb
= ((float)b
* (Pcsi
.nb
-1))/255;
493 if (PMappingTable
!= NULL
)
495 ir
= (int)fr
+ (fr
- (int)fr
> 0.5);
496 ig
= (int)fg
+ (fg
- (int)fg
> 0.5);
497 ib
= (int)fb
+ (fb
- (int)fb
> 0.5);
499 index
= ir
* Pcsi
.ng
*Pcsi
.nb
+ ig
* Pcsi
.nb
+ ib
;
503 /* found the best of the 8 linear closest points */
504 int lr
,lg
,lb
,tr
,tg
,tb
,best_dist
= -1,i
,d
;
507 lr
= min((int)fr
+1,Pcsi
.nr
-1);
508 lg
= min((int)fg
+1,Pcsi
.ng
-1);
509 lb
= min((int)fb
+1,Pcsi
.nb
-1);
510 for(tr
=(int)fr
; tr
<=lr
; tr
++)
512 for(tg
=(int)fg
; tg
<=lg
; tg
++)
514 for(tb
=(int)fb
; tb
<=lb
; tb
++)
516 i
= tr
* Pcsi
.ng
*Pcsi
.nb
+
521 (Pct
[i
].color
.red
>>8),
522 (Pct
[i
].color
.green
>>8),
523 (Pct
[i
].color
.blue
>>8));
524 if (best_dist
== -1 ||
534 /* now found the best grey */
535 if (Pcsi
.ngrey
- 2 > 0)
537 /* FIXME: speedup this with more than 8 grey */
538 int start
= Pcsi
.nr
*Pcsi
.ng
*Pcsi
.nb
;
539 for(i
=start
; i
< start
+Pcsi
.ngrey
-2; i
++)
543 (Pct
[i
].color
.red
>>8),
544 (Pct
[i
].color
.green
>>8),
545 (Pct
[i
].color
.blue
>>8));
556 /* approximation; faster */
557 index
= ((r
* Pcsi
.nr
)>>8) * Pcsi
.ng
*Pcsi
.nb
+
558 ((g
* Pcsi
.ng
)>>8) * Pcsi
.nb
+
561 if (PMappingTable
!= NULL
)
563 index
= PMappingTable
[index
];
569 /* ***************************************************************************
570 * Main colors allocator
571 * ***************************************************************************/
573 int alloc_color_proportion(Display
*dpy
, Colormap cmap
, XColor
*c
)
576 ((c
->red
>> (16 - Pcsi
.red_prec
))<< Pcsi
.red_shift
) +
577 ((c
->green
>> (16 - Pcsi
.green_prec
))<< Pcsi
.green_shift
) +
578 ((c
->blue
>> (16 - Pcsi
.blue_prec
))<< Pcsi
.blue_shift
)
584 int alloc_color_proportion_dither(
585 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
)
587 /* 8 bit colors !! */
588 c
->red
= Pcsi
.red_dither
[
589 (((x
+ 0) & 0x3) << 10) | ((y
& 0x3) << 8) |
590 ((c
->red
) & 0xff)] * 257;
591 c
->green
= Pcsi
.green_dither
[
592 (((x
+ 0) & 0x3) << 10) | ((y
& 0x3) << 8) |
593 ((c
->green
) & 0xff)] * 257;
594 c
->blue
= Pcsi
.blue_dither
[
595 (((x
+ 0) & 0x3) << 10) | ((y
& 0x3) << 8) |
596 ((c
->blue
) & 0xff)] * 257;
598 ((c
->red
>> (16 - Pcsi
.red_prec
)) << Pcsi
.red_shift
) +
599 ((c
->green
>> (16 - Pcsi
.green_prec
))
600 << Pcsi
.green_shift
) +
601 ((c
->blue
>> (16 - Pcsi
.blue_prec
)) << Pcsi
.blue_shift
)
607 int alloc_color_proportion_grey(
608 Display
*dpy
, Colormap cmap
, XColor
*c
)
610 /* FIXME: is this ok in general? */
611 c
->pixel
= ((c
->red
+ c
->green
+ c
->blue
)/3);
614 c
->pixel
= c
->pixel
>> (16 - Pdepth
);
620 int alloc_color_in_table(Display
*dpy
, Colormap cmap
, XColor
*c
)
623 int index
= get_color_index(c
->red
,c
->green
,c
->blue
, False
);
624 return alloc_color_in_pct(c
, index
);
628 int alloc_color_in_table_dither(
629 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
)
632 /* 8 bit colors !! */
633 index
= my_dither(x
, y
, c
);
634 return alloc_color_in_pct(c
, index
);
638 int alloc_color_dynamic_no_limit(
639 Display
*dpy
, Colormap cmap
, XColor
*c
)
643 if (XAllocColor(dpy
, cmap
, c
))
647 else if (!alloc_color_in_cmap(c
, False
))
650 r
= alloc_color_in_cmap(c
, True
);
657 if (r
&& Pac
!= NULL
&& (c
->pixel
<= (1 << Pdepth
) /* always true*/))
659 Pac
[c
->pixel
].alloc_count
++;
660 Pac
[c
->pixel
].color
.red
= c
->red
;
661 Pac
[c
->pixel
].color
.green
= c
->green
;
662 Pac
[c
->pixel
].color
.blue
= c
->blue
;
663 Pac
[c
->pixel
].color
.pixel
= c
->pixel
;
670 Display
*dpy
, Colormap cmap
, XColor
*c
)
672 return XAllocColor(dpy
, cmap
, c
);
676 void free_colors_in_table(
677 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
, unsigned long planes
,
684 if (!Pct
|| !PUseDynamicColors
)
689 p
= (Pixel
*)safemalloc(n
*sizeof(Pixel
));
690 for(i
= 0; i
< n
; i
++)
693 for(j
=0; j
<PColorLimit
; j
++)
695 if (Pct
[j
].alloc_count
&&
696 Pct
[j
].alloc_count
< 0xffffffff &&
697 pixels
[i
] == Pct
[j
].color
.pixel
)
699 (Pct
[j
].alloc_count
)--;
700 if (Pct
[j
].alloc_count
)
712 XFreeColors(dpy
, cmap
, p
, m
, planes
);
721 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
, unsigned long planes
,
724 XFreeColors(dpy
, cmap
, pixels
, n
, planes
);
727 int nbr_colors
= (1 << Pdepth
);
730 for(i
= 0; i
< n
; i
++)
732 if (pixels
[i
] <= nbr_colors
)
734 Pac
[pixels
[i
]].alloc_count
--;
740 /* ***************************************************************************
741 * local function for building pallet (dynamic colors, private DirectColor
743 * ***************************************************************************/
745 XColor
*build_mapping_colors(int nr
, int ng
, int nb
)
750 colors
= (XColor
*)safemalloc(nr
*ng
*nb
* sizeof(XColor
));
752 for (r
= 0; r
< nr
; r
++)
754 for (g
= 0; g
< ng
; g
++)
756 for (b
= 0; b
< nb
; b
++)
759 r
* 65535 / (nr
- 1);
761 g
* 65535 / (ng
- 1);
763 b
* 65535 / (nb
- 1);
771 short *build_mapping_table(int nr
, int ng
, int nb
, Bool use_named
)
777 double mindst
= 40000;
780 colors_map
= build_mapping_colors(nr
, ng
, nb
);
781 Table
= (short *)safemalloc((size
+1) * sizeof(short));
782 for(i
=0; i
<size
; i
++)
785 for(j
=0; j
<PColorLimit
; j
++)
789 /* for back ward compatibility */
790 dst
= TRUE_DIST(colors_map
[i
].red
,
799 dst
= USED_DIST(colors_map
[i
].red
,
806 if (j
== 0 || dst
< mindst
)
814 Table
[size
] = Table
[size
-1];
820 void free_table_colors(PColor
*color_table
, int npixels
)
827 for(i
= 0; i
< npixels
; i
++)
829 if (color_table
[i
].alloc_count
)
831 pixels
[n
++] = color_table
[i
].color
.pixel
;
833 color_table
[i
].alloc_count
= 0;
837 XFreeColors(Pdpy
, Pcmap
, pixels
, n
, 0);
842 /* FIXME: the DirectColor case */
844 int get_nbr_of_free_colors(int max_check
)
848 int map_entries
= (Pvisual
->class == DirectColor
)?
849 (1 << Pdepth
):Pvisual
->map_entries
;
852 if (map_entries
> 256)
856 max_check
= (max_check
> map_entries
) ? map_entries
:max_check
;
859 if (XAllocColorCells(
860 Pdpy
, Pcmap
, False
, NULL
, 0, Pixels
, check
))
862 XFreeColors(Pdpy
, Pcmap
, Pixels
, check
, 0);
869 if (check
> max_check
)
878 PColor
*alloc_color_cube(
879 int nr
, int ng
, int nb
, int ngrey
, int grey_bits
, Bool do_allocate
)
881 int r
, g
, b
, grey
, i
, start_grey
, end_grey
;
886 size
= nr
*ng
*nb
+ ngrey
+ (1 << grey_bits
)*(grey_bits
!= 0);
889 ngrey
= (1 << grey_bits
);
891 if (nr
> 0 && ngrey
> 0)
894 end_grey
= ngrey
- 1;
903 color_table
= (PColor
*)safemalloc((size
+1) * sizeof(PColor
));
907 #if USE_GAMMA_CORECTION
908 #define CG(x) 65535.0 * pow((x)/65535.0,1/COLOR_GAMMA)
909 #define GG(x) 65535.0 * pow((x)/65535.0,1/GREY_GAMMA)
917 for (r
= 0; r
< nr
; r
++)
919 for (g
= 0; g
< ng
; g
++)
921 for (b
= 0; b
< nb
; b
++)
923 color
.red
= CG(r
* 65535 / (nr
- 1));
924 color
.green
= CG(g
* 65535 / (ng
- 1));
925 color
.blue
= CG(b
* 65535 / (nb
- 1));
928 if (!XAllocColor(Pdpy
, Pcmap
,
936 color_table
[i
].color
.pixel
=
938 color_table
[i
].alloc_count
= 1;
942 color_table
[i
].alloc_count
= 0;
944 color_table
[i
].color
.red
= color
.red
;
945 color_table
[i
].color
.green
= color
.green
;
946 color_table
[i
].color
.blue
= color
.blue
;
955 for (grey
= start_grey
; grey
< end_grey
; grey
++)
957 color
.red
= color
.green
= color
.blue
=
958 GG(grey
* 65535 / (ngrey
- 1));
961 if (!XAllocColor(Pdpy
, Pcmap
, &color
))
963 free_table_colors(color_table
, i
);
967 color_table
[i
].color
.pixel
= color
.pixel
;
968 color_table
[i
].alloc_count
= 1;
972 color_table
[i
].alloc_count
= 0;
974 color_table
[i
].color
.red
= color
.red
;
975 color_table
[i
].color
.green
= color
.green
;
976 color_table
[i
].color
.blue
= color
.blue
;
980 color_table
[size
].color
.red
= color_table
[size
-1].color
.red
;
981 color_table
[size
].color
.green
= color_table
[size
-1].color
.green
;
982 color_table
[size
].color
.blue
= color_table
[size
-1].color
.blue
;
983 color_table
[size
].color
.pixel
= color_table
[size
-1].color
.pixel
;
984 color_table
[size
].alloc_count
= 0;
991 PColor
*alloc_named_ct(int *limit
, Bool do_allocate
)
994 /* First thing in base array are colors probably already in the color map
995 because they have familiar names.
996 I pasted them into a xpm and spread them out so that similar colors are
998 Toward the end are some colors to fill in the gaps.
999 Currently 61 colors in this list.
1001 char *color_names
[] =
1044 "salmon", /* for peachpuff, orange gap */
1045 "blue4", /* for navyblue/mediumblue gap */
1046 "PaleGreen4", /* for forestgreen, yellowgreen gap */
1047 "#AA7700", /* brick, no close named color */
1048 "#11EE88", /* light green, no close named color */
1049 "#884466", /* dark brown, no close named color */
1050 "#CC8888", /* light brick, no close named color */
1051 "#EECC44", /* gold, no close named color */
1052 "#AAAA44", /* dull green, no close named color */
1053 "#FF1188", /* pinkish red */
1054 "#992299", /* purple */
1055 "#CCFFAA", /* light green */
1056 "#664400", /* dark brown*/
1057 "#AADD99", /* light green */
1058 "#66CCFF", /* light blue */
1059 "#CC2299", /* dark red */
1060 "#FF11CC", /* bright pink */
1061 "#11CC99", /* grey/green */
1062 "#AA77AA", /* purple/red */
1063 "#EEBB77" /* orange/yellow */
1065 int NColors
= sizeof(color_names
)/sizeof(char *);
1067 PColor
*color_table
;
1070 *limit
= (*limit
> NColors
)? NColors
: *limit
;
1071 color_table
= (PColor
*)safemalloc((*limit
+1) * sizeof(PColor
));
1072 for(i
=0; i
<*limit
; i
++)
1074 rc
=XParseColor(Pdpy
, Pcmap
, color_names
[i
], &color
);
1076 fprintf(stderr
,"color_to_rgb: can't parse color %s,"
1077 " rc %d\n", color_names
[i
], rc
);
1078 free_table_colors(color_table
, i
);
1084 if (!XAllocColor(Pdpy
, Pcmap
, &color
))
1086 free_table_colors(color_table
, i
);
1090 color_table
[i
].color
.pixel
= color
.pixel
;
1091 color_table
[i
].alloc_count
= 1;
1095 color_table
[i
].alloc_count
= 0;
1097 color_table
[i
].color
.red
= color
.red
;
1098 color_table
[i
].color
.green
= color
.green
;
1099 color_table
[i
].color
.blue
= color
.blue
;
1101 color_table
[*limit
].color
.red
= color_table
[*limit
-1].color
.red
;
1102 color_table
[*limit
].color
.green
= color_table
[*limit
-1].color
.green
;
1103 color_table
[*limit
].color
.blue
= color_table
[*limit
-1].color
.blue
;
1104 color_table
[*limit
].color
.pixel
= color_table
[*limit
-1].color
.pixel
;
1105 color_table
[*limit
].alloc_count
= 0;
1106 PColorLimit
= *limit
;
1111 void create_mapping_table(
1112 int nr
, int ng
, int nb
, int ngrey
, int grey_bits
,
1113 Bool non_regular_pallet
)
1118 /* initialize dithering colors numbers */
1119 if (!non_regular_pallet
)
1125 Pcsi
.d_ngrey_bits
= 2;
1126 while((1<<Pcsi
.d_ngrey_bits
) < ngrey
)
1128 Pcsi
.d_ngrey_bits
++;
1130 if (1<<Pcsi
.d_ngrey_bits
!= ngrey
)
1132 Pcsi
.d_ngrey_bits
= 0;
1134 Pcsi
.grey_bits
= grey_bits
;
1138 /* dither table should be small */
1140 if (PColorLimit
<= 9)
1145 Pcsi
.d_ngrey_bits
= 0;
1147 else if (PColorLimit
<= 64)
1152 Pcsi
.d_ngrey_bits
= 0;
1159 Pcsi
.d_ngrey_bits
= 0;
1161 PDitherMappingTable
= build_mapping_table(
1162 Pcsi
.d_nr
, Pcsi
.d_ng
, Pcsi
.d_nb
, non_regular_pallet
);
1165 /* initialize colors number fo index computation */
1166 if (PColorLimit
== 2)
1175 else if (grey_bits
> 0)
1181 Pcsi
.grey_bits
= grey_bits
;
1183 else if (non_regular_pallet
|| (0&&ngrey
>0))
1185 /* note: using these table with !used_named && ngrey>0 will
1186 * probably leads to faster image loading. But I see nothing
1187 * of significative. On the others hands not using it gives
1188 * maybe better colors approximation. */
1189 if (PColorLimit
<= 9)
1203 PMappingTable
= build_mapping_table(
1204 Pcsi
.nr
, Pcsi
.ng
, Pcsi
.nb
, non_regular_pallet
);
1216 void finish_ct_init(
1217 int call_type
, int ctt
, int nr
, int ng
, int nb
, int ngrey
, int grey_bits
,
1220 if (call_type
== PICTURE_CALLED_BY_FVWM
)
1226 ctt
= PICTURE_PAllocTable
+ ctt
;
1228 if (PUseDynamicColors
)
1230 ctt
= PICTURE_PUseDynamicColors
+ ctt
;
1232 if (PStrictColorLimit
)
1234 ctt
= PICTURE_PStrictColorLimit
+ ctt
;
1238 ctt
= PICTURE_use_named
+ ctt
;
1244 env
= safemalloc(21+PICTURE_TABLETYPE_LENGHT
+1);
1245 sprintf(env
,"FVWM_COLORTABLE_TYPE=%i",ctt
);
1249 Pac
= (PColor
*)safecalloc(
1250 (1 << Pdepth
), sizeof(PColor
));
1256 if (!PAllocTable
&& call_type
== PICTURE_CALLED_BY_FVWM
)
1258 free_table_colors(Pct
, PColorLimit
);
1260 create_mapping_table(nr
,ng
,nb
,ngrey
,grey_bits
,use_named
);
1264 #define PA_COLOR_CUBE (1 << 1)
1265 #define FVWM_COLOR_CUBE (1 << 2)
1266 #define PA_GRAY_SCALE (1 << 3)
1267 #define FVWM_GRAY_SCALE (1 << 4)
1268 #define ANY_COLOR_CUBE (PA_COLOR_CUBE|FVWM_COLOR_CUBE)
1269 #define ANY_GRAY_SCALE (PA_GRAY_SCALE|FVWM_GRAY_SCALE)
1272 int PictureAllocColorTable(
1273 PictureColorLimitOption
*opt
, int call_type
, Bool use_my_color_limit
)
1276 int free_colors
, nbr_of_color
, limit
, cc_nbr
, i
, size
;
1277 int use_named_table
= 0;
1278 int do_allocate
= 0;
1279 int use_default
= 1;
1280 int private_cmap
= !(Pdefault
);
1281 int dyn_cl_set
= False
;
1282 int strict_cl_set
= False
;
1283 int alloc_table_set
= False
;
1285 int pa_type
= (Pvisual
->class != GrayScale
)? PA_COLOR_CUBE
:PA_GRAY_SCALE
;
1286 int fvwm_type
= (Pvisual
->class != GrayScale
)?
1287 FVWM_COLOR_CUBE
:FVWM_GRAY_SCALE
;
1290 /* {nr,ng,nb,ngrey,grey_bits,logic} */
1291 /* 5 first for direct colors and Pdepth > 8*/
1292 /* 8192 colors depth 13, a reasonable max for a color table */
1293 {16, 32, 16, 0, 0, FVWM_COLOR_CUBE
},
1294 /* 4096 colors depth 12 */
1295 {16, 16, 16, 0, 0, FVWM_COLOR_CUBE
},
1296 /* 1024 colors depth 10 */
1297 {8, 16, 8, 0, 0, FVWM_COLOR_CUBE
},
1298 /* 512 colors depth 9 */
1299 {8, 8, 8, 0, 0, FVWM_COLOR_CUBE
},
1300 /* 256 colors 3/3/2 standard colormap */
1301 {8, 8, 4, 0, 0, FVWM_COLOR_CUBE
},
1302 /* 256 grey scale */
1303 {0, 0, 0, 0, 8, ANY_GRAY_SCALE
},
1304 /* 244 Xrender XFree-4.2 */
1305 {6, 6, 6, 30, 0, ANY_COLOR_CUBE
},
1306 /* 216 Xrender XFree-4.2,GTK/QT "default cc" */
1307 {6, 6, 6, 0, 0, ANY_COLOR_CUBE
},
1309 {6, 6, 5, 0, 0, ANY_COLOR_CUBE
},
1311 {6, 6, 4, 0, 0, ANY_COLOR_CUBE
},
1312 /* 128 grey scale */
1313 {0, 0, 0, 0, 7, ANY_GRAY_SCALE
},
1314 /* 125 GTK mini default cc (may change? 444) */
1315 {5, 5, 5, 0, 0, ANY_COLOR_CUBE
},
1316 /* 100 (GTK with color limit) */
1317 {5, 5, 4, 0, 0, ANY_COLOR_CUBE
},
1318 /* 85 Xrender XFree-4.3 */
1319 {4, 4, 4, 23, 0, ANY_COLOR_CUBE
},
1320 /* 78 (in fact 76) a good default ??*/
1321 {4, 4, 4, 16, 0, FVWM_COLOR_CUBE
},
1322 /* 70 a good default ?? */
1323 {4, 4, 4, 8, 0, ANY_COLOR_CUBE
},
1324 /* 68 a good default ?? */
1325 {4, 4, 4, 6, 0, ANY_COLOR_CUBE
},
1326 /* 64 Xrender XFree-4.3 (GTK wcl) */
1327 {4, 4, 4, 0, 0, ANY_COLOR_CUBE
},
1329 {0, 0, 0, 0, 6, ANY_GRAY_SCALE
},
1330 /* 54, maybe a good default? */
1331 {4, 4, 3, 8, 0, FVWM_COLOR_CUBE
},
1332 /* 48, (GTK wcl) no grey but ok */
1333 {4, 4, 3, 0, 0, FVWM_COLOR_CUBE
},
1334 /* 32, 2/2/1 standard colormap */
1335 {4, 4, 2, 0, 0, FVWM_COLOR_CUBE
},
1336 /* 32 xrender xfree-4.2 */
1337 {0, 0, 0, 0, 6, ANY_GRAY_SCALE
},
1339 {3, 3, 3, 4, 0, FVWM_COLOR_CUBE
},
1340 /* 27 (xrender in depth 6&7(hypo) GTK wcl) */
1341 {3, 3, 3, 0, 0, FVWM_COLOR_CUBE
|PA_COLOR_CUBE
*(Pdepth
<8)},
1343 {0, 0, 0, 0, 4, FVWM_GRAY_SCALE
},
1345 {2, 2, 2, 4, 0, FVWM_COLOR_CUBE
},
1346 /* 8 (xrender/qt/gtk wcl) */
1347 {2, 2, 2, 0, 0, FVWM_COLOR_CUBE
},
1348 /* 8 grey scale Xrender depth 4 and XFree-4.3 */
1349 {0, 0, 0, 0, 3, FVWM_GRAY_SCALE
|PA_GRAY_SCALE
*(Pdepth
<5)},
1352 FVWM_GRAY_SCALE
|FVWM_COLOR_CUBE
|PA_COLOR_CUBE
*(Pdepth
<4)},
1354 {0, 0, 0, 0, 1, FVWM_COLOR_CUBE
|FVWM_GRAY_SCALE
}
1357 cc_nbr
= sizeof(cc
)/(sizeof(cc
[0]));
1359 /* set up default */
1360 PStrictColorLimit
= 0;
1361 PUseDynamicColors
= 1;
1363 use_named_table
= False
;
1367 /* use fvwm color limit */
1368 if (!use_my_color_limit
&&
1369 (envp
= getenv("FVWM_COLORTABLE_TYPE")) != NULL
)
1371 int nr
= 0, ng
= 0, nb
= 0, grey_bits
= 0, ngrey
= 0;
1372 int ctt
= atoi(envp
);
1374 if (ctt
>= PICTURE_PAllocTable
)
1376 ctt
-= PICTURE_PAllocTable
;
1377 PAllocTable
= 1; /* not useful for a module !*/
1379 if (ctt
>= PICTURE_PUseDynamicColors
)
1381 PUseDynamicColors
= 1;
1382 ctt
-= PICTURE_PUseDynamicColors
;
1384 if (ctt
>= PICTURE_PStrictColorLimit
)
1386 PStrictColorLimit
= 1;
1387 ctt
-= PICTURE_PStrictColorLimit
;
1389 if (ctt
>= PICTURE_use_named
)
1391 ctt
-= PICTURE_use_named
;
1392 Pct
= alloc_named_ct(&ctt
, False
);
1393 use_named_table
= True
;
1397 /* depth <= 8 and no colors limit ! */
1401 else if (ctt
<= cc_nbr
)
1404 Pct
= alloc_color_cube(
1405 cc
[ctt
][0], cc
[ctt
][1], cc
[ctt
][2], cc
[ctt
][3],
1412 grey_bits
= cc
[ctt
][4];
1416 /* should always happen */
1418 call_type
, ctt
, nr
, ng
, nb
, ngrey
, grey_bits
,
1424 nbr_of_color
= (1 << Pdepth
);
1427 /* parse the color limit env variable */
1428 if ((envp
= getenv("FVWM_COLORLIMIT")) != NULL
)
1432 rest
= GetQuotedString(envp
, &l
, ":", NULL
, NULL
, NULL
);
1433 if (l
&& *l
!= '\0' && (color_limit
= atoi(l
)) >= 0)
1441 if (color_limit
== 9 || color_limit
== 61)
1443 use_named_table
= 1;
1445 if (rest
&& *rest
!= '\0')
1449 strict_cl_set
= True
;
1450 PStrictColorLimit
= 1;
1454 strict_cl_set
= True
;
1455 PStrictColorLimit
= 0;
1457 if (strlen(rest
) > 1 && rest
[1] == '1')
1459 use_named_table
= 1;
1463 use_named_table
= 0;
1465 if (strlen(rest
) > 2 && rest
[2] == '1')
1468 PUseDynamicColors
= 1;
1473 PUseDynamicColors
= 0;
1475 if (strlen(rest
) > 3 && rest
[3] == '1')
1477 alloc_table_set
= True
;
1482 alloc_table_set
= True
;
1487 else if (opt
!= NULL
) /* use the option */
1489 if (opt
->color_limit
> 0)
1492 color_limit
= opt
->color_limit
;
1494 if (color_limit
== 9 || color_limit
== 61)
1496 use_named_table
= 1;
1498 if (opt
->strict
> 0)
1500 strict_cl_set
= True
;
1501 PStrictColorLimit
= 1;
1503 else if (opt
->strict
== 0)
1505 strict_cl_set
= True
;
1506 PStrictColorLimit
= 0;
1508 if (opt
->use_named_table
> 0)
1510 use_named_table
= 1;
1512 else if (opt
->use_named_table
== 0)
1514 use_named_table
= 0;
1516 if (opt
->not_dynamic
> 0)
1519 PUseDynamicColors
= 0;
1521 else if (opt
->not_dynamic
== 0)
1524 PUseDynamicColors
= 0;
1526 if (opt
->allocate
> 0)
1528 alloc_table_set
= True
;
1531 else if (opt
->allocate
== 0)
1533 alloc_table_set
= True
;
1538 if (color_limit
<= 0)
1541 color_limit
= nbr_of_color
;
1544 /* first try to see if we have a "pre-allocated" color cube.
1545 * The bultin RENDER X extension pre-allocate a color cube plus
1546 * some grey's (xc/programs/Xserver/render/miindex)
1547 * See gdk/gdkrgb.c for the cubes used by gtk+-2, 666 is the default,
1548 * 555 is the minimal cc (this may change): if gtk cannot allocate
1549 * the 555 cc (or better) a private cmap is used.
1550 * for qt-3: see src/kernel/{qapplication.cpp,qimage.cpp,qcolor_x11.c}
1551 * the 666 cube is used by default (with approx in the cmap if some
1552 * color allocation fail), and some qt app may accept an
1553 * --ncols option to limit the nbr of colors, then some "2:3:1"
1554 * proportions color cube are used (222, 232, ..., 252, 342, ..., 362,
1555 * 452, ...,693, ...)
1556 * imlib2 try to allocate the 666 cube if this fail it try more
1557 * exotic table (see rend.c and rgba.c) */
1560 if (Pdepth
<= 8 && !private_cmap
&& use_default
&&
1561 i
< cc_nbr
&& Pct
== NULL
&& (Pvisual
->class & 1))
1563 free_colors
= get_nbr_of_free_colors(nbr_of_color
);
1565 while(Pdepth
<= 8 && !private_cmap
&& use_default
&&
1566 i
< cc_nbr
&& Pct
== NULL
&& (Pvisual
->class & 1))
1568 size
= cc
[i
][0]*cc
[i
][1]*cc
[i
][2] + cc
[i
][3] - 2*(cc
[i
][3] > 0) +
1569 (1 << cc
[i
][4])*(cc
[i
][4] != 0);
1570 if (size
> nbr_of_color
|| !(cc
[i
][5] & pa_type
))
1575 if (free_colors
<= nbr_of_color
- size
)
1577 Pct
= alloc_color_cube(
1578 cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3], cc
[i
][4],
1584 get_nbr_of_free_colors(nbr_of_color
))
1590 free_table_colors(Pct
, PColorLimit
);
1599 PUseDynamicColors
= 0;
1601 Pcsi
.pre_allocated_pallet
= 1;
1604 call_type
, i
, cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3],
1610 * now use "our" table
1613 limit
= (color_limit
>= nbr_of_color
)? nbr_of_color
:color_limit
;
1615 if (use_default
&& !private_cmap
)
1617 /* XRender cvs default: */
1620 limit
= nbr_of_color
/3;
1622 limit
= nbr_of_color
/2;
1628 /* direct colors & Pdepth > 8 */
1633 else if (Pdepth
>= 15)
1642 else if (limit
== 256)
1644 if (Pvisual
->class == GrayScale
)
1648 else if (Pvisual
->class == DirectColor
)
1656 * limit = 54; 4x4x3 + 6 grey
1657 * limit = 61 (named table)
1658 * limit = 85 current XRender default 4cc + 21
1659 * limit = 76 future(?) XRender default 4cc + 16
1660 * limit = 68 4x4x4 + 4
1661 * limit = 64 4x4x4 + 0 */
1665 else if (limit
== 128 || limit
== 64)
1667 if (Pvisual
->class == GrayScale
)
1676 else if (limit
>= 16)
1678 if (Pvisual
->class == GrayScale
)
1687 else if (limit
>= 8)
1701 if (Pvisual
->class == DirectColor
)
1703 /* humm ... Any way this case should never happen in real life:
1704 * DirectColor default colormap! */
1705 PUseDynamicColors
= 0;
1707 PStrictColorLimit
= 1;
1718 /* use the named table ? */
1719 if (use_named_table
)
1722 while(Pct
== NULL
&& i
>= 2)
1724 Pct
= alloc_named_ct(&i
, do_allocate
);
1731 call_type
, PColorLimit
, 0, 0, 0, 0, 0, 1);
1735 /* color cube or regular grey scale */
1737 while(i
< cc_nbr
&& Pct
== NULL
)
1739 if ((cc
[i
][5] & fvwm_type
) &&
1740 cc
[i
][0]*cc
[i
][1]*cc
[i
][2] + cc
[i
][3] - 2*(cc
[i
][3] > 0) +
1741 (1 << cc
[i
][4])*(cc
[i
][4] != 0) <= limit
)
1743 Pct
= alloc_color_cube(
1744 cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3], cc
[i
][4],
1753 call_type
, i
, cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3],
1758 /* I do not think we can be here */
1759 Pct
= alloc_color_cube(0, 0, 0, 0, 1, False
);
1760 finish_ct_init(call_type
, cc_nbr
-1, 0, 0, 0, 0, 1, 0);
1764 "[FVWM] ERR -- Cannot get Black and White. exiting!\n");
1770 /* ***************************************************************************
1771 * Allocation of a private DirectColor cmap this is broken for depth > 16
1772 * ***************************************************************************/
1774 Bool
alloc_direct_colors(int *limit
, Bool use_my_color_limit
)
1776 unsigned long nr
,ng
,nb
,r
,g
,b
,cr
,cg
,cf
,pr
,pg
;
1777 unsigned long red_mask
, green_mask
, blue_mask
;
1782 red_mask
= Pvisual
->red_mask
;
1783 green_mask
= Pvisual
->green_mask
;
1784 blue_mask
= Pvisual
->blue_mask
;
1788 /* Use a standard depth 16 colormap. This is broken FIXME! */
1795 red_mask
, &Pcsi
.red_shift
, &Pcsi
.red_prec
);
1797 green_mask
, &Pcsi
.green_shift
, &Pcsi
.green_prec
);
1799 blue_mask
, &Pcsi
.blue_shift
, &Pcsi
.blue_prec
);
1801 if (!use_my_color_limit
)
1803 /* colors allocated by fvwm we can return */
1807 nr
= 1 << Pcsi
.red_prec
;
1808 ng
= 1 << Pcsi
.green_prec
;
1809 nb
= 1 << Pcsi
.blue_prec
;
1811 colors
= (XColor
*)safemalloc(nb
*sizeof(XColor
));
1812 cf
= DoRed
|DoBlue
|DoGreen
;
1813 for (r
=0; r
<nr
; r
++)
1815 cr
= r
* 65535 / (nr
- 1);
1816 pr
= (cr
>> (16 - Pcsi
.red_prec
)) << Pcsi
.red_shift
;
1817 for (g
= 0; g
< ng
; g
++)
1819 cg
= g
* 65535 / (ng
- 1);
1820 pg
= (cg
>> (16 - Pcsi
.green_prec
)) << Pcsi
.green_shift
;
1821 for (b
= 0; b
< nb
; b
++)
1823 colors
[b
].flags
= cf
;
1825 colors
[b
].green
= cg
;
1826 colors
[b
].blue
= b
* 65535 / (nb
- 1);
1830 (16 - Pcsi
.blue_prec
)) <<
1833 XStoreColors(Pdpy
, Pcmap
, colors
, nb
);
1840 /* ***************************************************************************
1841 * Init the table for Static Colors
1842 * ***************************************************************************/
1844 void init_static_colors_table(void)
1848 int nbr_of_colors
= max(256, (1 << Pdepth
));
1850 PColorLimit
= nbr_of_colors
;
1851 Pct
= (PColor
*)safemalloc((nbr_of_colors
+1) * sizeof(PColor
));
1852 for (i
= 0; i
< nbr_of_colors
; i
++)
1854 colors
[i
].pixel
= Pct
[i
].color
.pixel
= i
;
1856 XQueryColors(Pdpy
, Pcmap
, colors
, nbr_of_colors
);
1857 for (i
= 0; i
< nbr_of_colors
; i
++)
1859 Pct
[i
].color
.red
= colors
[i
].red
;
1860 Pct
[i
].color
.green
= colors
[i
].green
;
1861 Pct
[i
].color
.blue
= colors
[i
].blue
;
1862 Pct
[i
].alloc_count
= 1;
1864 Pct
[PColorLimit
].color
.red
= Pct
[PColorLimit
-1].color
.red
;
1865 Pct
[PColorLimit
].color
.green
= Pct
[PColorLimit
-1].color
.green
;
1866 Pct
[PColorLimit
].color
.blue
= Pct
[PColorLimit
-1].color
.blue
;
1867 Pct
[PColorLimit
].alloc_count
= 1;
1868 create_mapping_table(0, 0, 0, 0, 0, True
);
1872 /* ***************************************************************************
1873 * misc local functions
1874 * ***************************************************************************/
1876 void print_colormap(Colormap cmap
)
1880 int nbr_of_colors
= max(256, (1 << Pdepth
));
1881 for (i
= 0; i
< nbr_of_colors
; i
++)
1883 colors
[i
].pixel
= i
;
1885 XQueryColors(Pdpy
, cmap
, colors
, nbr_of_colors
);
1886 for (i
= 0; i
< nbr_of_colors
; i
++)
1888 fprintf(stderr
," rgb(%.3i): %.3i/%.3i/%.3i\n", i
,
1890 colors
[i
].green
>> 8,
1891 colors
[i
].blue
>> 8);
1895 /* ---------------------------- interface functions ------------------------- */
1897 int PictureAllocColor(Display
*dpy
, Colormap cmap
, XColor
*c
, int no_limit
)
1899 if (PStrictColorLimit
&& Pct
!= NULL
)
1906 return Pcsi
.alloc_color_no_limit(dpy
, cmap
, c
);
1910 return Pcsi
.alloc_color(dpy
, cmap
, c
);
1916 int PictureAllocColorAllProp(
1917 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
,
1918 Bool no_limit
, Bool is_8
, Bool do_dither
)
1921 if (!no_limit
&& do_dither
&& Pcsi
.alloc_color_dither
!= NULL
)
1925 c
->red
= c
->red
>> 8;
1926 c
->green
= c
->green
>> 8;
1927 c
->blue
= c
->blue
>> 8;
1929 return Pcsi
.alloc_color_dither(dpy
, cmap
, c
, x
, y
);
1935 c
->red
= c
->red
<< 8;
1936 c
->green
= c
->green
<< 8;
1937 c
->blue
= c
->blue
<< 8;
1939 return PictureAllocColor(dpy
, cmap
, c
, False
);
1944 int PictureAllocColorImage(
1945 Display
*dpy
, PictureImageColorAllocator
*pica
, XColor
*c
, int x
, int y
)
1949 r
= PictureAllocColorAllProp(
1950 dpy
, pica
->cmap
, c
, x
, y
,
1951 pica
->no_limit
, pica
->is_8
, pica
->dither
);
1952 if (r
&& pica
->pixels_table
!= NULL
&& pica
->pixels_table_size
&&
1953 c
->pixel
< pica
->pixels_table_size
)
1955 pica
->pixels_table
[c
->pixel
]++;
1960 PictureImageColorAllocator
*PictureOpenImageColorAllocator(
1961 Display
*dpy
, Colormap cmap
, int x
, int y
, Bool no_limit
,
1962 Bool do_not_save_pixels
, int dither
, Bool is_8
)
1964 PictureImageColorAllocator
*pica
;
1965 Bool do_save_pixels
= False
;
1967 pica
= (PictureImageColorAllocator
*)safemalloc(
1968 sizeof(PictureImageColorAllocator
));
1969 if (Pdepth
<= 8 && !do_not_save_pixels
&& (Pvisual
->class & 1) &&
1970 ((PUseDynamicColors
&& Pct
) || no_limit
))
1972 int s
= 1 << Pdepth
;
1973 pica
->pixels_table
= (unsigned long *)safecalloc(
1974 s
, sizeof(unsigned long));
1975 pica
->pixels_table_size
= s
;
1976 do_save_pixels
= True
;
1978 if (!do_save_pixels
)
1980 pica
->pixels_table
= NULL
;
1981 pica
->pixels_table_size
= 0;
1984 if (dither
&& Pdepth
<= 16)
1986 pica
->dither
= dither
;
1990 pica
->dither
= dither
;
1992 pica
->no_limit
= no_limit
;
1997 void PictureCloseImageColorAllocator(
1998 Display
*dpy
, PictureImageColorAllocator
*pica
, int *nalloc_pixels
,
1999 Pixel
**alloc_pixels
, Bool
*no_limit
)
2005 if (alloc_pixels
!= NULL
)
2007 *alloc_pixels
= NULL
;
2009 if (no_limit
!= NULL
)
2013 if (pica
->pixels_table
)
2016 int k
= 0, l
= 0, np
= 0;
2018 Pixel
*free_pixels
= NULL
;
2019 Pixel
*save_pixels
= NULL
;
2021 for(i
= 0; i
< pica
->pixels_table_size
; i
++)
2023 if (pica
->pixels_table
[i
])
2025 free_num
+= (pica
->pixels_table
[i
]-1);
2031 free_pixels
= (Pixel
*)safemalloc(
2032 free_num
* sizeof(Pixel
));
2034 if (np
&& nalloc_pixels
!= NULL
&& alloc_pixels
!= NULL
)
2036 save_pixels
= (Pixel
*)safemalloc(np
* sizeof(Pixel
));
2038 for(i
= 0; i
< pica
->pixels_table_size
; i
++)
2040 if (pica
->pixels_table
[i
])
2044 save_pixels
[k
++] = i
;
2046 for(j
=1; j
< pica
->pixels_table
[i
]; j
++)
2048 free_pixels
[l
++] = i
;
2055 dpy
, pica
->cmap
, free_pixels
, free_num
, 0,
2059 if (nalloc_pixels
!= NULL
&& alloc_pixels
!= NULL
)
2061 *nalloc_pixels
= np
;
2062 *alloc_pixels
= save_pixels
;
2063 if (no_limit
!= NULL
)
2065 *no_limit
= pica
->no_limit
;
2068 else if (save_pixels
)
2072 free(pica
->pixels_table
);
2078 void PictureFreeColors(
2079 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
, unsigned long planes
,
2084 if (Pcsi
.free_colors_no_limit
!= NULL
)
2086 Pcsi
.free_colors_no_limit(
2087 dpy
, cmap
, pixels
, n
, planes
);
2092 if (Pcsi
.free_colors
!= NULL
)
2094 Pcsi
.free_colors(dpy
, cmap
, pixels
, n
, planes
);
2100 Pixel
PictureGetNextColor(Pixel p
, int n
)
2114 for(i
=0; i
<PColorLimit
; i
++)
2116 if (Pct
[i
].color
.pixel
== p
)
2118 if (i
== 0 && n
< 0)
2120 c
= Pct
[PColorLimit
-1].color
;
2121 alloc_color_in_pct(&c
, PColorLimit
-1);
2122 return Pct
[PColorLimit
-1].color
.pixel
;
2124 else if (i
== PColorLimit
-1 && n
> 0)
2127 alloc_color_in_pct(&c
, 0);
2128 return Pct
[0].color
.pixel
;
2133 alloc_color_in_pct(&c
, i
+n
);
2134 return Pct
[i
+n
].color
.pixel
;
2141 /* Replace the color in my_color by the closest matching color
2143 void PictureReduceColorName(char **my_color
)
2146 XColor rgb
; /* place to calc rgb for each color in xpm */
2151 if (!strcasecmp(*my_color
,"none")) {
2152 return; /* do not substitute the "none" color */
2155 if (!XParseColor(Pdpy
, Pcmap
, *my_color
, &rgb
))
2157 fprintf(stderr
,"color_to_rgb: can't parse color %s\n",
2160 index
= get_color_index(rgb
.red
,rgb
.green
,rgb
.blue
, False
);
2161 /* Finally: replace the color string by the newly determined color
2163 free(*my_color
); /* free old color */
2164 /* area for new color */
2165 *my_color
= safemalloc(8);
2166 sprintf(*my_color
,"#%x%x%x",
2167 Pct
[index
].color
.red
>> 8,
2168 Pct
[index
].color
.green
>> 8,
2169 Pct
[index
].color
.blue
>> 8); /* put it there */
2173 Bool
PictureDitherByDefault(void)
2182 Bool
PictureUseBWOnly(void)
2184 if (Pdepth
< 2 || (PStrictColorLimit
&& PColorLimit
== 2))
2191 int PictureInitColors(
2192 int call_type
, Bool init_color_limit
, PictureColorLimitOption
*opt
,
2193 Bool use_my_color_limit
, Bool init_dither
)
2195 Bool dither_ok
= False
;
2197 switch (Pvisual
->class)
2200 /* direct colors is more or less broken */
2202 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2205 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2208 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2210 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2211 Pcsi
.alloc_color
= alloc_color_proportion
;
2212 Pcsi
.alloc_color_dither
= alloc_color_proportion_dither
;
2213 Pcsi
.free_colors_no_limit
= NULL
;
2214 Pcsi
.free_colors
= NULL
;
2219 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2222 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2225 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2227 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2228 Pcsi
.alloc_color
= alloc_color_proportion
;
2229 Pcsi
.free_colors_no_limit
= NULL
;
2230 Pcsi
.free_colors
= NULL
;
2232 if (init_dither
&& (Pdepth
== 15 || Pdepth
== 16))
2234 dither_ok
= my_dither_depth_15_16_init();
2238 Pcsi
.alloc_color_dither
= alloc_color_proportion_dither
;
2242 Pcsi
.alloc_color_dither
= NULL
;
2246 if (0 && Pvisual
->red_mask
!= 0 && Pvisual
->green_mask
!= 0 &&
2247 Pvisual
->blue_mask
!= 0)
2250 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2253 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2256 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2258 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2259 Pcsi
.alloc_color
= alloc_color_proportion
;
2264 if (init_color_limit
)
2266 Pcsi
.alloc_color
= alloc_color_in_table
;
2267 Pcsi
.alloc_color_dither
=
2268 alloc_color_in_table_dither
;
2269 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2270 init_static_colors_table();
2274 Pcsi
.alloc_color
= alloc_color_x
;
2275 Pcsi
.alloc_color_dither
= NULL
;
2276 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2279 Pcsi
.free_colors_no_limit
= NULL
;
2280 Pcsi
.free_colors
= NULL
;
2283 /* FIXME: we assume that we have a regular grey ramp */
2286 Pcsi
.alloc_color_no_limit
= alloc_color_proportion_grey
;
2287 Pcsi
.alloc_color
= alloc_color_proportion
;
2292 if (init_color_limit
)
2294 Pcsi
.alloc_color
= alloc_color_in_table
;
2295 Pcsi
.alloc_color_dither
=
2296 alloc_color_in_table_dither
;
2297 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2298 init_static_colors_table();
2302 Pcsi
.alloc_color
= alloc_color_x
;
2303 Pcsi
.alloc_color_dither
= NULL
;
2304 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2307 Pcsi
.free_colors_no_limit
= NULL
;
2308 Pcsi
.free_colors
= NULL
;
2313 Pcsi
.alloc_color_no_limit
= alloc_color_dynamic_no_limit
;
2314 Pcsi
.free_colors_no_limit
= free_colors_x
;
2318 if (!(Pvisual
->class & 1))
2320 /* static classes */
2321 PUseDynamicColors
= 0;
2322 if (call_type
== PICTURE_CALLED_BY_FVWM
&&
2323 getenv("FVWM_COLORTABLE_TYPE") != NULL
)
2325 putenv("FVWM_COLORTABLE_TYPE=");
2330 /* dynamic classes */
2332 if (!Pdefault
&& Pvisual
->class == DirectColor
)
2335 PUseDynamicColors
= 0;
2336 alloc_direct_colors(0, use_my_color_limit
);
2337 if (call_type
== PICTURE_CALLED_BY_FVWM
&&
2338 getenv("FVWM_COLORTABLE_TYPE") != NULL
)
2340 putenv("FVWM_COLORTABLE_TYPE=");
2346 if (init_color_limit
)
2348 Pcsi
.alloc_color
= alloc_color_in_table
;
2349 Pcsi
.alloc_color_dither
= alloc_color_in_table_dither
;
2350 PictureAllocColorTable(opt
, call_type
, use_my_color_limit
);
2351 if (PUseDynamicColors
)
2353 Pcsi
.free_colors
= free_colors_in_table
;
2357 Pcsi
.free_colors
= NULL
;
2362 Pcsi
.alloc_color
= alloc_color_dynamic_no_limit
;
2363 Pcsi
.free_colors
= free_colors_x
;
2364 Pcsi
.alloc_color_dither
= NULL
;
2369 void PicturePrintColorInfo(int verbose
)
2371 unsigned long nbr_of_colors
= 1 << Pdepth
;
2373 fprintf(stderr
, "FVWM info on colors\n");
2374 fprintf(stderr
, " Visual ID: 0x%x, Default?: %s, Class: ",
2375 (int)(Pvisual
->visualid
),
2376 (Pdefault
)? "Yes":"No");
2377 if (Pvisual
->class == TrueColor
)
2379 fprintf(stderr
,"TrueColor");
2381 else if (Pvisual
->class == PseudoColor
)
2383 fprintf(stderr
,"PseudoColor");
2385 else if (Pvisual
->class == DirectColor
)
2387 fprintf(stderr
,"DirectColor");
2389 else if (Pvisual
->class == StaticColor
)
2391 fprintf(stderr
,"StaticColor");
2393 else if (Pvisual
->class == GrayScale
)
2395 fprintf(stderr
,"GrayScale");
2397 else if (Pvisual
->class == StaticGray
)
2399 fprintf(stderr
,"StaticGray");
2401 fprintf(stderr
, "\n");
2402 fprintf(stderr
, " Depth: %i, Number of colors: %lu",
2403 Pdepth
, (unsigned long)nbr_of_colors
);
2406 fprintf(stderr
,"\n Pallet with %i colors", PColorLimit
);
2407 if (Pvisual
->class & 1)
2409 fprintf(stderr
,", Number of free colors: %i\n",
2410 get_nbr_of_free_colors((1 << Pdepth
)));
2412 " Auto Detected: %s, Strict: %s, Allocated: %s,"
2414 (Pcsi
.pre_allocated_pallet
)? "Yes":"No",
2415 (PStrictColorLimit
)? "Yes":"No",
2416 (PAllocTable
)? "Yes":"No",
2417 (PUseDynamicColors
)? "Yes":"No");
2421 fprintf(stderr
," (default colormap)\n");
2423 if (PColorLimit
<= 256)
2427 int count_alloc
= 0;
2431 fprintf(stderr
," The fvwm colors table:\n");
2433 for (i
= 0; i
< PColorLimit
; i
++)
2439 " rgb:%.3i/%.3i/%.3i\t%lu\n",
2440 Pct
[i
].color
.red
>> 8,
2441 Pct
[i
].color
.green
>> 8,
2442 Pct
[i
].color
.blue
>> 8,
2443 Pct
[i
].alloc_count
);
2445 if (Pct
[i
].alloc_count
)
2450 if ((Pvisual
->class & 1) && Pac
!= NULL
)
2454 fprintf(stderr
," fvwm colors not in"
2457 for(i
=0; i
< nbr_of_colors
; i
++)
2462 if (!Pac
[i
].alloc_count
)
2464 while(j
< PColorLimit
&& !found
)
2466 if (i
== Pct
[j
].color
.pixel
)
2480 "%.3i/%.3i/%.3i\t%lu\n",
2481 Pac
[i
].color
.red
>> 8,
2482 Pac
[i
].color
.green
>> 8,
2483 Pac
[i
].color
.blue
>> 8,
2484 Pac
[i
].alloc_count
);
2487 if (verbose
&& count_alloc
== 0)
2491 fprintf(stderr
," None\n");
2495 if (Pvisual
->class & 1)
2498 " Number of colours used by fvwm:\n");
2500 " In the table: %i\n", count
);
2502 stderr
, " Out of the table: %i\n",
2505 " Total: %i\n", count_alloc
+count
);
2511 if (Pvisual
->class == DirectColor
)
2513 fprintf(stderr
, ", Pseudo Pallet with: %i colors\n",
2514 (1 << Pcsi
.red_prec
)*(1 << Pcsi
.green_prec
)*
2515 (1 << Pcsi
.blue_prec
));
2519 fprintf(stderr
, ", No Pallet (static colors)\n");
2521 fprintf(stderr
, " red: %i, green: %i, blue %i\n",
2522 1 << Pcsi
.red_prec
, 1 << Pcsi
.green_prec
,
2523 1 << Pcsi
.blue_prec
);
2524 if (verbose
&& Pdepth
<= 8)
2526 if (Pvisual
->class == DirectColor
)
2528 fprintf(stderr
, " Colormap:\n");
2533 " Static Colormap used by fvwm:\n");
2535 print_colormap(Pcmap
);
2539 if (Pdepth
<= 8 && verbose
>= 2)
2541 fprintf(stderr
,"\n Default Colormap:\n");
2542 print_colormap(DefaultColormap(Pdpy
,DefaultScreen(Pdpy
)));