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.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /* ---------------------------- included header files ---------------------- */
35 #include "PictureBase.h"
36 #include "PictureUtils.h"
37 #include "PictureDitherMatrice.h"
39 /* ---------------------------- local definitions and macro ----------------- */
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
53 #define SQUARE(X) ((X)*(X))
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)))
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)))
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)))
70 #define USED_DIST(r1,g1,b1,r2,g2,b2) FVWM_DIST(r1,g1,b1,r2,g2,b2)
72 #define PICTURE_COLOR_CLOSENESS USED_DIST(3,3,3,0,0,0)
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
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
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
89 /* ---------------------------- imports ------------------------------------ */
91 /* ---------------------------- included code files ------------------------ */
93 /* ---------------------------- local types -------------------------------- */
97 XColor color
; /* rgb color info */
98 unsigned long alloc_count
; /* nbr of allocation */
104 * info for colors table (depth <= 8)
106 /* color cube used */
111 /* grey palette def, nbr of grey = 2^grey_bits */
113 /* color cube used for dithering with the named table */
118 /* do we found a pre-allocated pallet ? */
119 Bool pre_allocated_pallet
;
120 /* info for depth > 8 */
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
);
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
);
149 /* ---------------------------- forward declarations ----------------------- */
151 /* ---------------------------- local variables ---------------------------- */
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
};
164 /* ---------------------------- exported variables (globals) --------------- */
166 /* ---------------------------- local functions ---------------------------- */
169 * get shift and prec from a mask
173 unsigned long mask
, int *shift
, int *prec
)
178 while (!(mask
& 0x1))
192 * color allocation in the colormap. strongly inspired by SetCloseColor from
193 * the Xpm library (depth <= 8)
197 closeness_cmp(const void *a
, const void *b
)
199 CloseColor
*x
= (CloseColor
*) a
, *y
= (CloseColor
*) b
;
201 /* cast to int as qsort requires */
202 return (int) (x
->closeness
- y
->closeness
);
206 int alloc_color_in_cmap(XColor
*c
, Bool force
)
208 static XColor colors
[256];
209 CloseColor closenesses
[256];
212 int map_entries
= (Pvisual
->class == DirectColor
)?
213 (1 << Pdepth
) : Pvisual
->map_entries
;
215 time_t last_time
= 0;
217 map_entries
= (map_entries
> 256)? 256:map_entries
;
218 current_time
= time(NULL
);
219 if (current_time
- last_time
>= 2 || force
)
221 last_time
= current_time
;
222 for (i
= 0; i
< map_entries
; i
++)
226 XQueryColors(Pdpy
, Pcmap
, colors
, map_entries
);
228 for(i
= 0; i
< map_entries
; i
++)
230 closenesses
[i
].cols_index
= i
;
231 closenesses
[i
].closeness
= USED_DIST(
235 (int)(colors
[i
].red
),
236 (int)(colors
[i
].green
),
237 (int)(colors
[i
].blue
));
239 qsort(closenesses
, map_entries
, sizeof(CloseColor
), closeness_cmp
);
242 j
= closenesses
[i
].cols_index
;
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
))
251 tmp
.red
= colors
[j
].red
;
252 tmp
.green
= colors
[j
].green
;
253 tmp
.blue
= colors
[j
].blue
;
254 if (XAllocColor(Pdpy
, Pcmap
, &tmp
))
257 c
->green
= tmp
.green
;
259 c
->pixel
= tmp
.pixel
;
265 if (i
== map_entries
)
267 j
= closenesses
[i
].cols_index
;
278 int my_dither(int x
, int y
, XColor
*c
)
280 /* the dither matrice */
281 static const char DM
[128][128] = DITHER_MATRICE
;
285 if (Pcsi
.grey_bits
!= 0)
288 int prec
= Pcsi
.grey_bits
;
290 if (Pcsi
.grey_bits
== 1)
292 /* FIXME, can we do a better dithering */
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
);
304 int dith
, rs
, gs
, bs
, gb
, b
;
310 gb
= Pcsi
.d_ng
*Pcsi
.d_nb
;
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
;
320 /* try to use the additonal grey. Not easy, good for
321 * certain image/gradient bad for others */
322 if (Pcsi
.d_ngrey_bits
)
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;
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
) <=
338 g_index
= g_index
+ Pcsi
.ng
*Pcsi
.nb
*Pcsi
.ng
-1;
343 if (PDitherMappingTable
!= NULL
)
345 index
= PDitherMappingTable
[index
];
352 int my_dither_depth_15_16_init(void)
354 const unsigned char _dither_44
[4][4] =
362 int rm
= 0xf8, re
= 0x7, gm
= 0xfc, ge
= 0x3, bm
= 0xf8, be
= 0x7;
364 if (Pdepth
== 16 && (Pvisual
->red_mask
== 0xf800) &&
365 (Pvisual
->green_mask
== 0x7e0) &&
366 (Pvisual
->blue_mask
== 0x1f))
370 else if (Pdepth
== 15 && (Pvisual
->red_mask
== 0x7c00) &&
371 (Pvisual
->green_mask
== 0x3e0) &&
372 (Pvisual
->blue_mask
== 0x1f))
382 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
384 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
386 (unsigned short *)safemalloc(4*4*256*sizeof(unsigned short));
388 for (y
= 0; y
< 4; y
++)
390 for (x
= 0; x
< 4; x
++)
392 for (i
= 0; i
< 256; i
++)
394 if ((_dither_44
[x
][y
] < (i
& re
)) &&
398 (x
<< 10) | (y
<< 8) | i
] =
404 (x
<< 10) | (y
<< 8) | i
] =
407 if ((_dither_44
[x
][y
] < ((i
& ge
) << 1))
411 (x
<< 10) | (y
<< 8) | i
] =
417 (x
<< 10) | (y
<< 8) | i
] =
420 if ((_dither_44
[x
][y
] < (i
& be
)) &&
424 (x
<< 10) | (y
<< 8) | i
] =
430 (x
<< 10) | (y
<< 8) | i
] =
440 * Color allocation in the "palette"
444 int alloc_color_in_pct(XColor
*c
, int index
)
446 if (Pct
[index
].alloc_count
== 0)
448 int s
= PStrictColorLimit
;
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
;
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
)++;
472 int get_color_index(int r
, int g
, int b
, int is_8
)
482 if (Pcsi
.grey_bits
> 0)
484 /* FIXME: Use other proporition ? */
485 index
= ((r
+g
+b
)/3) >> (8 - Pcsi
.grey_bits
);
490 /* "exact" computation (corrected linear dist) */
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;
499 if (PMappingTable
!= NULL
)
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);
505 index
= ir
* Pcsi
.ng
*Pcsi
.nb
+ ig
* Pcsi
.nb
+ ib
;
509 /* found the best of the 8 linear closest points */
510 int lr
,lg
,lb
,tr
,tg
,tb
,best_dist
= -1,i
,d
;
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
++)
518 for(tg
=(int)fg
; tg
<=lg
; tg
++)
520 for(tb
=(int)fb
; tb
<=lb
; tb
++)
522 i
= tr
* Pcsi
.ng
*Pcsi
.nb
+
527 (Pct
[i
].color
.red
>>8),
528 (Pct
[i
].color
.green
>>8),
529 (Pct
[i
].color
.blue
>>8));
530 if (best_dist
== -1 ||
540 /* now found the best grey */
541 if (Pcsi
.ngrey
- 2 > 0)
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
++)
549 (Pct
[i
].color
.red
>>8),
550 (Pct
[i
].color
.green
>>8),
551 (Pct
[i
].color
.blue
>>8));
562 /* approximation; faster */
563 index
= ((r
* Pcsi
.nr
)>>8) * Pcsi
.ng
*Pcsi
.nb
+
564 ((g
* Pcsi
.ng
)>>8) * Pcsi
.nb
+
567 if (PMappingTable
!= NULL
)
569 index
= PMappingTable
[index
];
576 * Main colors allocator
579 int alloc_color_proportion(Display
*dpy
, Colormap cmap
, XColor
*c
)
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
)
590 int alloc_color_proportion_dither(
591 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
)
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;
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
)
613 int alloc_color_proportion_grey(
614 Display
*dpy
, Colormap cmap
, XColor
*c
)
616 /* FIXME: is this ok in general? */
617 c
->pixel
= ((c
->red
+ c
->green
+ c
->blue
)/3);
620 c
->pixel
= c
->pixel
>> (16 - Pdepth
);
626 int alloc_color_in_table(Display
*dpy
, Colormap cmap
, XColor
*c
)
629 int index
= get_color_index(c
->red
,c
->green
,c
->blue
, False
);
630 return alloc_color_in_pct(c
, index
);
634 int alloc_color_in_table_dither(
635 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
)
638 /* 8 bit colors !! */
639 index
= my_dither(x
, y
, c
);
640 return alloc_color_in_pct(c
, index
);
644 int alloc_color_dynamic_no_limit(
645 Display
*dpy
, Colormap cmap
, XColor
*c
)
649 if (XAllocColor(dpy
, cmap
, c
))
653 else if (!alloc_color_in_cmap(c
, False
))
656 r
= alloc_color_in_cmap(c
, True
);
663 if (r
&& Pac
!= NULL
&& (c
->pixel
<= (1 << Pdepth
) /* always true*/))
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
;
676 Display
*dpy
, Colormap cmap
, XColor
*c
)
678 return XAllocColor(dpy
, cmap
, c
);
682 void free_colors_in_table(
683 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
,
684 unsigned long planes
)
690 if (!Pct
|| !PUseDynamicColors
)
695 p
= (Pixel
*)safemalloc(n
*sizeof(Pixel
));
696 for(i
= 0; i
< n
; i
++)
699 for(j
=0; j
<PColorLimit
; j
++)
701 if (Pct
[j
].alloc_count
&&
702 Pct
[j
].alloc_count
< 0xffffffff &&
703 pixels
[i
] == Pct
[j
].color
.pixel
)
705 (Pct
[j
].alloc_count
)--;
706 if (Pct
[j
].alloc_count
)
718 XFreeColors(dpy
, cmap
, p
, m
, planes
);
727 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
,
728 unsigned long planes
)
730 XFreeColors(dpy
, cmap
, pixels
, n
, planes
);
733 int nbr_colors
= (1 << Pdepth
);
736 for(i
= 0; i
< n
; i
++)
738 if (pixels
[i
] <= nbr_colors
)
740 Pac
[pixels
[i
]].alloc_count
--;
747 * local function for building pallet (dynamic colors, private DirectColor
751 XColor
*build_mapping_colors(int nr
, int ng
, int nb
)
756 colors
= (XColor
*)safemalloc(nr
*ng
*nb
* sizeof(XColor
));
758 for (r
= 0; r
< nr
; r
++)
760 for (g
= 0; g
< ng
; g
++)
762 for (b
= 0; b
< nb
; b
++)
765 r
* 65535 / (nr
- 1);
767 g
* 65535 / (ng
- 1);
769 b
* 65535 / (nb
- 1);
777 static short *build_mapping_table(int nr
, int ng
, int nb
, Bool use_named
)
783 double mindst
= 40000;
786 colors_map
= build_mapping_colors(nr
, ng
, nb
);
787 Table
= (short *)safemalloc((size
+1) * sizeof(short));
788 for(i
=0; i
<size
; i
++)
791 for(j
=0; j
<PColorLimit
; j
++)
795 /* for back ward compatibility */
796 dst
= TRUE_DIST(colors_map
[i
].red
,
805 dst
= USED_DIST(colors_map
[i
].red
,
812 if (j
== 0 || dst
< mindst
)
820 Table
[size
] = Table
[size
-1];
826 void free_table_colors(PColor
*color_table
, int npixels
)
833 for(i
= 0; i
< npixels
; i
++)
835 if (color_table
[i
].alloc_count
)
837 pixels
[n
++] = color_table
[i
].color
.pixel
;
839 color_table
[i
].alloc_count
= 0;
843 XFreeColors(Pdpy
, Pcmap
, pixels
, n
, 0);
848 /* FIXME: the DirectColor case */
850 int get_nbr_of_free_colors(int max_check
)
854 int map_entries
= (Pvisual
->class == DirectColor
)?
855 (1 << Pdepth
):Pvisual
->map_entries
;
858 if (map_entries
> 256)
862 max_check
= (max_check
> map_entries
) ? map_entries
:max_check
;
865 if (XAllocColorCells(
866 Pdpy
, Pcmap
, False
, NULL
, 0, Pixels
, check
))
868 XFreeColors(Pdpy
, Pcmap
, Pixels
, check
, 0);
875 if (check
> max_check
)
884 PColor
*alloc_color_cube(
885 int nr
, int ng
, int nb
, int ngrey
, int grey_bits
, Bool do_allocate
)
887 int r
, g
, b
, grey
, i
, start_grey
, end_grey
;
892 size
= nr
*ng
*nb
+ ngrey
+ (1 << grey_bits
)*(grey_bits
!= 0);
895 ngrey
= (1 << grey_bits
);
897 if (nr
> 0 && ngrey
> 0)
900 end_grey
= ngrey
- 1;
909 color_table
= (PColor
*)safemalloc((size
+1) * sizeof(PColor
));
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)
923 for (r
= 0; r
< nr
; r
++)
925 for (g
= 0; g
< ng
; g
++)
927 for (b
= 0; b
< nb
; b
++)
929 color
.red
= CG(r
* 65535 / (nr
- 1));
930 color
.green
= CG(g
* 65535 / (ng
- 1));
931 color
.blue
= CG(b
* 65535 / (nb
- 1));
934 if (!XAllocColor(Pdpy
, Pcmap
,
942 color_table
[i
].color
.pixel
=
944 color_table
[i
].alloc_count
= 1;
948 color_table
[i
].alloc_count
= 0;
950 color_table
[i
].color
.red
= color
.red
;
951 color_table
[i
].color
.green
= color
.green
;
952 color_table
[i
].color
.blue
= color
.blue
;
961 for (grey
= start_grey
; grey
< end_grey
; grey
++)
963 color
.red
= color
.green
= color
.blue
=
964 GG(grey
* 65535 / (ngrey
- 1));
967 if (!XAllocColor(Pdpy
, Pcmap
, &color
))
969 free_table_colors(color_table
, i
);
973 color_table
[i
].color
.pixel
= color
.pixel
;
974 color_table
[i
].alloc_count
= 1;
978 color_table
[i
].alloc_count
= 0;
980 color_table
[i
].color
.red
= color
.red
;
981 color_table
[i
].color
.green
= color
.green
;
982 color_table
[i
].color
.blue
= color
.blue
;
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;
997 PColor
*alloc_named_ct(int *limit
, Bool do_allocate
)
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
1004 Toward the end are some colors to fill in the gaps.
1005 Currently 61 colors in this list.
1007 char *color_names
[] =
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 */
1071 int NColors
= sizeof(color_names
)/sizeof(char *);
1073 PColor
*color_table
;
1076 *limit
= (*limit
> NColors
)? NColors
: *limit
;
1077 color_table
= (PColor
*)safemalloc((*limit
+1) * sizeof(PColor
));
1078 for(i
=0; i
<*limit
; i
++)
1080 rc
=XParseColor(Pdpy
, Pcmap
, color_names
[i
], &color
);
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
);
1090 if (!XAllocColor(Pdpy
, Pcmap
, &color
))
1092 free_table_colors(color_table
, i
);
1096 color_table
[i
].color
.pixel
= color
.pixel
;
1097 color_table
[i
].alloc_count
= 1;
1101 color_table
[i
].alloc_count
= 0;
1103 color_table
[i
].color
.red
= color
.red
;
1104 color_table
[i
].color
.green
= color
.green
;
1105 color_table
[i
].color
.blue
= color
.blue
;
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
;
1117 void create_mapping_table(
1118 int nr
, int ng
, int nb
, int ngrey
, int grey_bits
,
1119 Bool non_regular_pallet
)
1124 /* initialize dithering colors numbers */
1125 if (!non_regular_pallet
)
1131 Pcsi
.d_ngrey_bits
= 2;
1132 while((1<<Pcsi
.d_ngrey_bits
) < ngrey
)
1134 Pcsi
.d_ngrey_bits
++;
1136 if (1<<Pcsi
.d_ngrey_bits
!= ngrey
)
1138 Pcsi
.d_ngrey_bits
= 0;
1140 Pcsi
.grey_bits
= grey_bits
;
1144 /* dither table should be small */
1146 if (PColorLimit
<= 9)
1151 Pcsi
.d_ngrey_bits
= 0;
1153 else if (PColorLimit
<= 64)
1158 Pcsi
.d_ngrey_bits
= 0;
1165 Pcsi
.d_ngrey_bits
= 0;
1167 PDitherMappingTable
= build_mapping_table(
1168 Pcsi
.d_nr
, Pcsi
.d_ng
, Pcsi
.d_nb
, non_regular_pallet
);
1171 /* initialize colors number fo index computation */
1172 if (PColorLimit
== 2)
1181 else if (grey_bits
> 0)
1187 Pcsi
.grey_bits
= grey_bits
;
1189 else if (non_regular_pallet
|| (0&&ngrey
>0))
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)
1209 PMappingTable
= build_mapping_table(
1210 Pcsi
.nr
, Pcsi
.ng
, Pcsi
.nb
, non_regular_pallet
);
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
)
1226 if (call_type
== PICTURE_CALLED_BY_FVWM
)
1232 ctt
= PICTURE_PAllocTable
+ ctt
;
1234 if (PUseDynamicColors
)
1236 ctt
= PICTURE_PUseDynamicColors
+ ctt
;
1238 if (PStrictColorLimit
)
1240 ctt
= PICTURE_PStrictColorLimit
+ ctt
;
1244 ctt
= PICTURE_use_named
+ ctt
;
1250 env
= safemalloc(PICTURE_TABLETYPE_LENGHT
+ 1);
1251 sprintf(env
, "%i", ctt
);
1252 flib_putenv("FVWM_COLORTABLE_TYPE", env
);
1256 Pac
= (PColor
*)safecalloc(
1257 (1 << Pdepth
), sizeof(PColor
));
1263 if (!PAllocTable
&& call_type
== PICTURE_CALLED_BY_FVWM
)
1265 free_table_colors(Pct
, PColorLimit
);
1267 create_mapping_table(nr
,ng
,nb
,ngrey
,grey_bits
,use_named
);
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)
1279 int PictureAllocColorTable(
1280 PictureColorLimitOption
*opt
, int call_type
, Bool use_my_color_limit
)
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 dyn_cl_set
= False
;
1289 int strict_cl_set
= False
;
1290 int alloc_table_set
= False
;
1292 int pa_type
= (Pvisual
->class != GrayScale
) ?
1293 PA_COLOR_CUBE
: PA_GRAY_SCALE
;
1294 int fvwm_type
= (Pvisual
->class != GrayScale
) ?
1295 FVWM_COLOR_CUBE
: FVWM_GRAY_SCALE
;
1298 /* {nr,ng,nb,ngrey,grey_bits,logic} */
1299 /* 5 first for direct colors and Pdepth > 8*/
1300 /* 8192 colors depth 13, a reasonable max for a color table */
1301 {16, 32, 16, 0, 0, FVWM_COLOR_CUBE
},
1302 /* 4096 colors depth 12 */
1303 {16, 16, 16, 0, 0, FVWM_COLOR_CUBE
},
1304 /* 1024 colors depth 10 */
1305 {8, 16, 8, 0, 0, FVWM_COLOR_CUBE
},
1306 /* 512 colors depth 9 */
1307 {8, 8, 8, 0, 0, FVWM_COLOR_CUBE
},
1308 /* 256 colors 3/3/2 standard colormap */
1309 {8, 8, 4, 0, 0, FVWM_COLOR_CUBE
},
1310 /* 256 grey scale */
1311 {0, 0, 0, 0, 8, ANY_GRAY_SCALE
},
1312 /* 244 Xrender XFree-4.2 */
1313 {6, 6, 6, 30, 0, ANY_COLOR_CUBE
},
1314 /* 216 Xrender XFree-4.2,GTK/QT "default cc" */
1315 {6, 6, 6, 0, 0, ANY_COLOR_CUBE
},
1317 {6, 6, 5, 0, 0, ANY_COLOR_CUBE
},
1319 {6, 6, 4, 0, 0, ANY_COLOR_CUBE
},
1320 /* 128 grey scale */
1321 {0, 0, 0, 0, 7, ANY_GRAY_SCALE
},
1322 /* 125 GTK mini default cc (may change? 444) */
1323 {5, 5, 5, 0, 0, ANY_COLOR_CUBE
},
1324 /* 100 (GTK with color limit) */
1325 {5, 5, 4, 0, 0, ANY_COLOR_CUBE
},
1326 /* 85 Xrender XFree-4.3 */
1327 {4, 4, 4, 23, 0, ANY_COLOR_CUBE
},
1328 /* 78 (in fact 76) a good default ??*/
1329 {4, 4, 4, 16, 0, FVWM_COLOR_CUBE
},
1330 /* 70 a good default ?? */
1331 {4, 4, 4, 8, 0, ANY_COLOR_CUBE
},
1332 /* 68 a good default ?? */
1333 {4, 4, 4, 6, 0, ANY_COLOR_CUBE
},
1334 /* 64 Xrender XFree-4.3 (GTK wcl) */
1335 {4, 4, 4, 0, 0, ANY_COLOR_CUBE
},
1337 {0, 0, 0, 0, 6, ANY_GRAY_SCALE
},
1338 /* 54, maybe a good default? */
1339 {4, 4, 3, 8, 0, FVWM_COLOR_CUBE
},
1340 /* 48, (GTK wcl) no grey but ok */
1341 {4, 4, 3, 0, 0, FVWM_COLOR_CUBE
},
1342 /* 32, 2/2/1 standard colormap */
1343 {4, 4, 2, 0, 0, FVWM_COLOR_CUBE
},
1344 /* 32 xrender xfree-4.2 */
1345 {0, 0, 0, 0, 6, ANY_GRAY_SCALE
},
1347 {3, 3, 3, 4, 0, FVWM_COLOR_CUBE
},
1348 /* 27 (xrender in depth 6&7(hypo) GTK wcl) */
1349 {3, 3, 3, 0, 0, FVWM_COLOR_CUBE
|PA_COLOR_CUBE
*(Pdepth
<8)},
1351 {0, 0, 0, 0, 4, FVWM_GRAY_SCALE
},
1353 {2, 2, 2, 4, 0, FVWM_COLOR_CUBE
},
1354 /* 8 (xrender/qt/gtk wcl) */
1355 {2, 2, 2, 0, 0, FVWM_COLOR_CUBE
},
1356 /* 8 grey scale Xrender depth 4 and XFree-4.3 */
1357 {0, 0, 0, 0, 3, FVWM_GRAY_SCALE
|PA_GRAY_SCALE
*(Pdepth
<5)},
1360 FVWM_GRAY_SCALE
|FVWM_COLOR_CUBE
|PA_COLOR_CUBE
*(Pdepth
<4)},
1362 {0, 0, 0, 0, 1, FVWM_COLOR_CUBE
|FVWM_GRAY_SCALE
}
1365 cc_nbr
= sizeof(cc
)/(sizeof(cc
[0]));
1367 /* set up default */
1368 PStrictColorLimit
= 0;
1369 PUseDynamicColors
= 1;
1371 use_named_table
= False
;
1375 /* use fvwm color limit */
1376 if (!use_my_color_limit
&&
1377 (envp
= getenv("FVWM_COLORTABLE_TYPE")) != NULL
)
1379 int nr
= 0, ng
= 0, nb
= 0, grey_bits
= 0, ngrey
= 0;
1380 int ctt
= atoi(envp
);
1382 if (ctt
>= PICTURE_PAllocTable
)
1384 ctt
-= PICTURE_PAllocTable
;
1385 PAllocTable
= 1; /* not useful for a module !*/
1387 if (ctt
>= PICTURE_PUseDynamicColors
)
1389 PUseDynamicColors
= 1;
1390 ctt
-= PICTURE_PUseDynamicColors
;
1392 if (ctt
>= PICTURE_PStrictColorLimit
)
1394 PStrictColorLimit
= 1;
1395 ctt
-= PICTURE_PStrictColorLimit
;
1397 if (ctt
>= PICTURE_use_named
)
1399 ctt
-= PICTURE_use_named
;
1400 Pct
= alloc_named_ct(&ctt
, False
);
1401 use_named_table
= True
;
1405 /* depth <= 8 and no colors limit ! */
1409 else if (ctt
<= cc_nbr
)
1412 Pct
= alloc_color_cube(
1413 cc
[ctt
][0], cc
[ctt
][1], cc
[ctt
][2], cc
[ctt
][3],
1420 grey_bits
= cc
[ctt
][4];
1424 /* should always happen */
1426 call_type
, ctt
, nr
, ng
, nb
, ngrey
, grey_bits
,
1432 nbr_of_color
= (1 << Pdepth
);
1435 /* parse the color limit env variable */
1436 if ((envp
= getenv("FVWM_COLORLIMIT")) != NULL
)
1440 rest
= GetQuotedString(envp
, &l
, ":", NULL
, NULL
, NULL
);
1441 if (l
&& *l
!= '\0' && (color_limit
= atoi(l
)) >= 0)
1449 if (color_limit
== 9 || color_limit
== 61)
1451 use_named_table
= 1;
1453 if (rest
&& *rest
!= '\0')
1457 strict_cl_set
= True
;
1458 PStrictColorLimit
= 1;
1462 strict_cl_set
= True
;
1463 PStrictColorLimit
= 0;
1465 if (strlen(rest
) > 1 && rest
[1] == '1')
1467 use_named_table
= 1;
1471 use_named_table
= 0;
1473 if (strlen(rest
) > 2 && rest
[2] == '1')
1476 PUseDynamicColors
= 1;
1481 PUseDynamicColors
= 0;
1483 if (strlen(rest
) > 3 && rest
[3] == '1')
1485 alloc_table_set
= True
;
1490 alloc_table_set
= True
;
1495 else if (opt
!= NULL
) /* use the option */
1497 if (opt
->color_limit
> 0)
1500 color_limit
= opt
->color_limit
;
1502 if (color_limit
== 9 || color_limit
== 61)
1504 use_named_table
= 1;
1506 if (opt
->strict
> 0)
1508 strict_cl_set
= True
;
1509 PStrictColorLimit
= 1;
1511 else if (opt
->strict
== 0)
1513 strict_cl_set
= True
;
1514 PStrictColorLimit
= 0;
1516 if (opt
->use_named_table
> 0)
1518 use_named_table
= 1;
1520 else if (opt
->use_named_table
== 0)
1522 use_named_table
= 0;
1524 if (opt
->not_dynamic
> 0)
1527 PUseDynamicColors
= 0;
1529 else if (opt
->not_dynamic
== 0)
1532 PUseDynamicColors
= 0;
1534 if (opt
->allocate
> 0)
1536 alloc_table_set
= True
;
1539 else if (opt
->allocate
== 0)
1541 alloc_table_set
= True
;
1546 if (color_limit
<= 0)
1549 color_limit
= nbr_of_color
;
1552 /* first try to see if we have a "pre-allocated" color cube.
1553 * The bultin RENDER X extension pre-allocate a color cube plus
1554 * some grey's (xc/programs/Xserver/render/miindex)
1555 * See gdk/gdkrgb.c for the cubes used by gtk+-2, 666 is the default,
1556 * 555 is the minimal cc (this may change): if gtk cannot allocate
1557 * the 555 cc (or better) a private cmap is used.
1558 * for qt-3: see src/kernel/{qapplication.cpp,qimage.cpp,qcolor_x11.c}
1559 * the 666 cube is used by default (with approx in the cmap if some
1560 * color allocation fail), and some qt app may accept an
1561 * --ncols option to limit the nbr of colors, then some "2:3:1"
1562 * proportions color cube are used (222, 232, ..., 252, 342, ..., 362,
1563 * 452, ...,693, ...)
1564 * imlib2 try to allocate the 666 cube if this fail it try more
1565 * exotic table (see rend.c and rgba.c) */
1568 if (Pdepth
<= 8 && !private_cmap
&& use_default
&&
1569 i
< cc_nbr
&& Pct
== NULL
&& (Pvisual
->class & 1))
1571 free_colors
= get_nbr_of_free_colors(nbr_of_color
);
1573 while(Pdepth
<= 8 && !private_cmap
&& use_default
&&
1574 i
< cc_nbr
&& Pct
== NULL
&& (Pvisual
->class & 1))
1576 size
= cc
[i
][0]*cc
[i
][1]*cc
[i
][2] + cc
[i
][3] -
1577 2*(cc
[i
][3] > 0) + (1 << cc
[i
][4])*(cc
[i
][4] != 0);
1578 if (size
> nbr_of_color
|| !(cc
[i
][5] & pa_type
))
1583 if (free_colors
<= nbr_of_color
- size
)
1585 Pct
= alloc_color_cube(
1586 cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3],
1592 get_nbr_of_free_colors(nbr_of_color
))
1598 free_table_colors(Pct
, PColorLimit
);
1607 PUseDynamicColors
= 0;
1609 Pcsi
.pre_allocated_pallet
= 1;
1612 call_type
, i
, cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3],
1618 * now use "our" table
1621 limit
= (color_limit
>= nbr_of_color
)? nbr_of_color
:color_limit
;
1623 if (use_default
&& !private_cmap
)
1625 /* XRender cvs default: */
1628 limit
= nbr_of_color
/3;
1630 limit
= nbr_of_color
/2;
1636 /* direct colors & Pdepth > 8 */
1641 else if (Pdepth
>= 15)
1650 else if (limit
== 256)
1652 if (Pvisual
->class == GrayScale
)
1656 else if (Pvisual
->class == DirectColor
)
1664 * limit = 54; 4x4x3 + 6 grey
1665 * limit = 61 (named table)
1666 * limit = 85 current XRender default 4cc + 21
1667 * limit = 76 future(?) XRender default 4cc + 16
1668 * limit = 68 4x4x4 + 4
1669 * limit = 64 4x4x4 + 0 */
1673 else if (limit
== 128 || limit
== 64)
1675 if (Pvisual
->class == GrayScale
)
1684 else if (limit
>= 16)
1686 if (Pvisual
->class == GrayScale
)
1695 else if (limit
>= 8)
1709 if (Pvisual
->class == DirectColor
)
1711 /* humm ... Any way this case should never happen in real life:
1712 * DirectColor default colormap! */
1713 PUseDynamicColors
= 0;
1715 PStrictColorLimit
= 1;
1726 /* use the named table ? */
1727 if (use_named_table
)
1730 while(Pct
== NULL
&& i
>= 2)
1732 Pct
= alloc_named_ct(&i
, do_allocate
);
1739 call_type
, PColorLimit
, 0, 0, 0, 0, 0, 1);
1743 /* color cube or regular grey scale */
1745 while(i
< cc_nbr
&& Pct
== NULL
)
1747 if ((cc
[i
][5] & fvwm_type
) &&
1748 cc
[i
][0]*cc
[i
][1]*cc
[i
][2] + cc
[i
][3] - 2*(cc
[i
][3] > 0) +
1749 (1 << cc
[i
][4])*(cc
[i
][4] != 0) <= limit
)
1751 Pct
= alloc_color_cube(
1752 cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3], cc
[i
][4],
1761 call_type
, i
, cc
[i
][0], cc
[i
][1], cc
[i
][2], cc
[i
][3],
1766 /* I do not think we can be here */
1767 Pct
= alloc_color_cube(0, 0, 0, 0, 1, False
);
1768 finish_ct_init(call_type
, cc_nbr
-1, 0, 0, 0, 0, 1, 0);
1772 "[FVWM] ERR -- Cannot get Black and White. exiting!\n");
1779 * Allocation of a private DirectColor cmap this is broken for depth > 16
1782 Bool
alloc_direct_colors(int *limit
, Bool use_my_color_limit
)
1784 unsigned long nr
,ng
,nb
,r
,g
,b
,cr
,cg
,cf
,pr
,pg
;
1785 unsigned long red_mask
, green_mask
, blue_mask
;
1790 red_mask
= Pvisual
->red_mask
;
1791 green_mask
= Pvisual
->green_mask
;
1792 blue_mask
= Pvisual
->blue_mask
;
1796 /* Use a standard depth 16 colormap. This is broken FIXME! */
1803 red_mask
, &Pcsi
.red_shift
, &Pcsi
.red_prec
);
1805 green_mask
, &Pcsi
.green_shift
, &Pcsi
.green_prec
);
1807 blue_mask
, &Pcsi
.blue_shift
, &Pcsi
.blue_prec
);
1809 if (!use_my_color_limit
)
1811 /* colors allocated by fvwm we can return */
1815 nr
= 1 << Pcsi
.red_prec
;
1816 ng
= 1 << Pcsi
.green_prec
;
1817 nb
= 1 << Pcsi
.blue_prec
;
1819 colors
= (XColor
*)safemalloc(nb
*sizeof(XColor
));
1820 cf
= DoRed
|DoBlue
|DoGreen
;
1821 for (r
=0; r
<nr
; r
++)
1823 cr
= r
* 65535 / (nr
- 1);
1824 pr
= (cr
>> (16 - Pcsi
.red_prec
)) << Pcsi
.red_shift
;
1825 for (g
= 0; g
< ng
; g
++)
1827 cg
= g
* 65535 / (ng
- 1);
1828 pg
= (cg
>> (16 - Pcsi
.green_prec
)) << Pcsi
.green_shift
;
1829 for (b
= 0; b
< nb
; b
++)
1831 colors
[b
].flags
= cf
;
1833 colors
[b
].green
= cg
;
1834 colors
[b
].blue
= b
* 65535 / (nb
- 1);
1838 (16 - Pcsi
.blue_prec
)) <<
1841 XStoreColors(Pdpy
, Pcmap
, colors
, nb
);
1849 * Init the table for Static Colors
1852 void init_static_colors_table(void)
1856 int nbr_of_colors
= min(256, (1 << Pdepth
));
1858 PColorLimit
= nbr_of_colors
;
1859 Pct
= (PColor
*)safemalloc((nbr_of_colors
+1) * sizeof(PColor
));
1860 for (i
= 0; i
< nbr_of_colors
; i
++)
1862 colors
[i
].pixel
= Pct
[i
].color
.pixel
= i
;
1864 XQueryColors(Pdpy
, Pcmap
, colors
, nbr_of_colors
);
1865 for (i
= 0; i
< nbr_of_colors
; i
++)
1867 Pct
[i
].color
.red
= colors
[i
].red
;
1868 Pct
[i
].color
.green
= colors
[i
].green
;
1869 Pct
[i
].color
.blue
= colors
[i
].blue
;
1870 Pct
[i
].alloc_count
= 1;
1872 Pct
[PColorLimit
].color
.red
= Pct
[PColorLimit
-1].color
.red
;
1873 Pct
[PColorLimit
].color
.green
= Pct
[PColorLimit
-1].color
.green
;
1874 Pct
[PColorLimit
].color
.blue
= Pct
[PColorLimit
-1].color
.blue
;
1875 Pct
[PColorLimit
].alloc_count
= 1;
1876 create_mapping_table(0, 0, 0, 0, 0, True
);
1881 * misc local functions
1884 void print_colormap(Colormap cmap
)
1888 int nbr_of_colors
= max(256, (1 << Pdepth
));
1889 for (i
= 0; i
< nbr_of_colors
; i
++)
1891 colors
[i
].pixel
= i
;
1893 XQueryColors(Pdpy
, cmap
, colors
, nbr_of_colors
);
1894 for (i
= 0; i
< nbr_of_colors
; i
++)
1896 fprintf(stderr
," rgb(%.3i): %.3i/%.3i/%.3i\n", i
,
1898 colors
[i
].green
>> 8,
1899 colors
[i
].blue
>> 8);
1903 /* ---------------------------- interface functions ------------------------ */
1905 int PictureAllocColor(Display
*dpy
, Colormap cmap
, XColor
*c
, int no_limit
)
1907 if (PStrictColorLimit
&& Pct
!= NULL
)
1914 return Pcsi
.alloc_color_no_limit(dpy
, cmap
, c
);
1918 return Pcsi
.alloc_color(dpy
, cmap
, c
);
1924 int PictureAllocColorAllProp(
1925 Display
*dpy
, Colormap cmap
, XColor
*c
, int x
, int y
,
1926 Bool no_limit
, Bool is_8
, Bool do_dither
)
1929 if (!no_limit
&& do_dither
&& Pcsi
.alloc_color_dither
!= NULL
)
1933 c
->red
= c
->red
>> 8;
1934 c
->green
= c
->green
>> 8;
1935 c
->blue
= c
->blue
>> 8;
1937 return Pcsi
.alloc_color_dither(dpy
, cmap
, c
, x
, y
);
1943 c
->red
= c
->red
<< 8;
1944 c
->green
= c
->green
<< 8;
1945 c
->blue
= c
->blue
<< 8;
1947 return PictureAllocColor(dpy
, cmap
, c
, False
);
1952 int PictureAllocColorImage(
1953 Display
*dpy
, PictureImageColorAllocator
*pica
, XColor
*c
, int x
, int y
)
1957 r
= PictureAllocColorAllProp(
1958 dpy
, pica
->cmap
, c
, x
, y
,
1959 pica
->no_limit
, pica
->is_8
, pica
->dither
);
1960 if (r
&& pica
->pixels_table
!= NULL
&& pica
->pixels_table_size
&&
1961 c
->pixel
< pica
->pixels_table_size
)
1963 pica
->pixels_table
[c
->pixel
]++;
1968 PictureImageColorAllocator
*PictureOpenImageColorAllocator(
1969 Display
*dpy
, Colormap cmap
, int x
, int y
, Bool no_limit
,
1970 Bool do_not_save_pixels
, int dither
, Bool is_8
)
1972 PictureImageColorAllocator
*pica
;
1973 Bool do_save_pixels
= False
;
1975 pica
= (PictureImageColorAllocator
*)safemalloc(
1976 sizeof(PictureImageColorAllocator
));
1977 if (Pdepth
<= 8 && !do_not_save_pixels
&& (Pvisual
->class & 1) &&
1978 ((PUseDynamicColors
&& Pct
) || no_limit
))
1980 int s
= 1 << Pdepth
;
1981 pica
->pixels_table
= (unsigned long *)safecalloc(
1982 s
, sizeof(unsigned long));
1983 pica
->pixels_table_size
= s
;
1984 do_save_pixels
= True
;
1986 if (!do_save_pixels
)
1988 pica
->pixels_table
= NULL
;
1989 pica
->pixels_table_size
= 0;
1992 if (dither
&& Pdepth
<= 16)
1994 pica
->dither
= dither
;
1998 pica
->dither
= dither
;
2000 pica
->no_limit
= no_limit
;
2005 void PictureCloseImageColorAllocator(
2006 Display
*dpy
, PictureImageColorAllocator
*pica
,
2007 int *nalloc_pixels
, Pixel
**alloc_pixels
, Bool
*no_limit
)
2013 if (alloc_pixels
!= NULL
)
2015 *alloc_pixels
= NULL
;
2017 if (no_limit
!= NULL
)
2021 if (pica
->pixels_table
)
2025 unsigned int np
= 0;
2027 Pixel
*free_pixels
= NULL
;
2028 Pixel
*save_pixels
= NULL
;
2030 for(i
= 0; i
< pica
->pixels_table_size
; i
++)
2032 if (pica
->pixels_table
[i
])
2034 free_num
+= (pica
->pixels_table
[i
]-1);
2040 free_pixels
= (Pixel
*)safemalloc(
2041 free_num
* sizeof(Pixel
));
2043 if (np
&& nalloc_pixels
!= NULL
&& alloc_pixels
!= NULL
)
2045 save_pixels
= (Pixel
*)safemalloc(np
* sizeof(Pixel
));
2047 for(i
= 0; i
< pica
->pixels_table_size
; i
++)
2049 if (pica
->pixels_table
[i
])
2053 save_pixels
[k
++] = i
;
2055 for(j
=1; j
< pica
->pixels_table
[i
]; j
++)
2057 free_pixels
[l
++] = i
;
2064 dpy
, pica
->cmap
, free_pixels
, free_num
, 0,
2068 if (nalloc_pixels
!= NULL
&& alloc_pixels
!= NULL
)
2070 *nalloc_pixels
= np
;
2071 *alloc_pixels
= save_pixels
;
2072 if (no_limit
!= NULL
)
2074 *no_limit
= pica
->no_limit
;
2077 else if (save_pixels
)
2081 free(pica
->pixels_table
);
2087 void PictureFreeColors(
2088 Display
*dpy
, Colormap cmap
, Pixel
*pixels
, int n
,
2089 unsigned long planes
, Bool no_limit
)
2093 if (Pcsi
.free_colors_no_limit
!= NULL
)
2095 Pcsi
.free_colors_no_limit(
2096 dpy
, cmap
, pixels
, n
, planes
);
2101 if (Pcsi
.free_colors
!= NULL
)
2103 Pcsi
.free_colors(dpy
, cmap
, pixels
, n
, planes
);
2109 Pixel
PictureGetNextColor(Pixel p
, int n
)
2123 for(i
=0; i
<PColorLimit
; i
++)
2125 if (Pct
[i
].color
.pixel
== p
)
2127 if (i
== 0 && n
< 0)
2129 c
= Pct
[PColorLimit
-1].color
;
2130 alloc_color_in_pct(&c
, PColorLimit
-1);
2131 return Pct
[PColorLimit
-1].color
.pixel
;
2133 else if (i
== PColorLimit
-1 && n
> 0)
2136 alloc_color_in_pct(&c
, 0);
2137 return Pct
[0].color
.pixel
;
2142 alloc_color_in_pct(&c
, i
+n
);
2143 return Pct
[i
+n
].color
.pixel
;
2150 /* Replace the color in my_color by the closest matching color
2152 void PictureReduceColorName(char **my_color
)
2155 XColor rgb
; /* place to calc rgb for each color in xpm */
2160 if (!strcasecmp(*my_color
,"none")) {
2161 return; /* do not substitute the "none" color */
2164 if (!XParseColor(Pdpy
, Pcmap
, *my_color
, &rgb
))
2166 fprintf(stderr
,"color_to_rgb: can't parse color %s\n",
2169 index
= get_color_index(rgb
.red
,rgb
.green
,rgb
.blue
, False
);
2170 /* Finally: replace the color string by the newly determined color
2172 free(*my_color
); /* free old color */
2173 /* area for new color */
2174 *my_color
= safemalloc(8);
2175 sprintf(*my_color
,"#%x%x%x",
2176 Pct
[index
].color
.red
>> 8,
2177 Pct
[index
].color
.green
>> 8,
2178 Pct
[index
].color
.blue
>> 8); /* put it there */
2182 Bool
PictureDitherByDefault(void)
2191 Bool
PictureUseBWOnly(void)
2193 if (Pdepth
< 2 || (PStrictColorLimit
&& PColorLimit
== 2))
2200 int PictureInitColors(
2201 int call_type
, Bool init_color_limit
, PictureColorLimitOption
*opt
,
2202 Bool use_my_color_limit
, Bool init_dither
)
2204 Bool dither_ok
= False
;
2206 switch (Pvisual
->class)
2209 /* direct colors is more or less broken */
2211 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2214 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2217 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2219 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2220 Pcsi
.alloc_color
= alloc_color_proportion
;
2221 Pcsi
.alloc_color_dither
= alloc_color_proportion_dither
;
2222 Pcsi
.free_colors_no_limit
= NULL
;
2223 Pcsi
.free_colors
= NULL
;
2228 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2231 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2234 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2236 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2237 Pcsi
.alloc_color
= alloc_color_proportion
;
2238 Pcsi
.free_colors_no_limit
= NULL
;
2239 Pcsi
.free_colors
= NULL
;
2241 if (init_dither
&& (Pdepth
== 15 || Pdepth
== 16))
2243 dither_ok
= my_dither_depth_15_16_init();
2247 Pcsi
.alloc_color_dither
= alloc_color_proportion_dither
;
2251 Pcsi
.alloc_color_dither
= NULL
;
2255 if (0 && Pvisual
->red_mask
!= 0 && Pvisual
->green_mask
!= 0 &&
2256 Pvisual
->blue_mask
!= 0)
2259 Pvisual
->red_mask
, &Pcsi
.red_shift
,
2262 Pvisual
->green_mask
, &Pcsi
.green_shift
,
2265 Pvisual
->blue_mask
, &Pcsi
.blue_shift
,
2267 Pcsi
.alloc_color_no_limit
= alloc_color_proportion
;
2268 Pcsi
.alloc_color
= alloc_color_proportion
;
2273 if (init_color_limit
)
2275 Pcsi
.alloc_color
= alloc_color_in_table
;
2276 Pcsi
.alloc_color_dither
=
2277 alloc_color_in_table_dither
;
2278 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2279 init_static_colors_table();
2283 Pcsi
.alloc_color
= alloc_color_x
;
2284 Pcsi
.alloc_color_dither
= NULL
;
2285 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2288 Pcsi
.free_colors_no_limit
= NULL
;
2289 Pcsi
.free_colors
= NULL
;
2292 /* FIXME: we assume that we have a regular grey ramp */
2295 Pcsi
.alloc_color_no_limit
= alloc_color_proportion_grey
;
2296 Pcsi
.alloc_color
= alloc_color_proportion
;
2301 if (init_color_limit
)
2303 Pcsi
.alloc_color
= alloc_color_in_table
;
2304 Pcsi
.alloc_color_dither
=
2305 alloc_color_in_table_dither
;
2306 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2307 init_static_colors_table();
2311 Pcsi
.alloc_color
= alloc_color_x
;
2312 Pcsi
.alloc_color_dither
= NULL
;
2313 Pcsi
.alloc_color_no_limit
= alloc_color_x
;
2316 Pcsi
.free_colors_no_limit
= NULL
;
2317 Pcsi
.free_colors
= NULL
;
2322 Pcsi
.alloc_color_no_limit
= alloc_color_dynamic_no_limit
;
2323 Pcsi
.free_colors_no_limit
= free_colors_x
;
2327 if (!(Pvisual
->class & 1))
2329 /* static classes */
2330 PUseDynamicColors
= 0;
2331 if (call_type
== PICTURE_CALLED_BY_FVWM
&&
2332 getenv("FVWM_COLORTABLE_TYPE") != NULL
)
2334 flib_putenv("FVWM_COLORTABLE_TYPE", "");
2339 /* dynamic classes */
2341 if (!Pdefault
&& Pvisual
->class == DirectColor
)
2344 PUseDynamicColors
= 0;
2345 alloc_direct_colors(0, use_my_color_limit
);
2346 if (call_type
== PICTURE_CALLED_BY_FVWM
&&
2347 getenv("FVWM_COLORTABLE_TYPE") != NULL
)
2349 flib_putenv("FVWM_COLORTABLE_TYPE", "");
2355 if (init_color_limit
)
2357 Pcsi
.alloc_color
= alloc_color_in_table
;
2358 Pcsi
.alloc_color_dither
= alloc_color_in_table_dither
;
2359 PictureAllocColorTable(opt
, call_type
, use_my_color_limit
);
2360 if (PUseDynamicColors
)
2362 Pcsi
.free_colors
= free_colors_in_table
;
2366 Pcsi
.free_colors
= NULL
;
2371 Pcsi
.alloc_color
= alloc_color_dynamic_no_limit
;
2372 Pcsi
.free_colors
= free_colors_x
;
2373 Pcsi
.alloc_color_dither
= NULL
;
2378 void PicturePrintColorInfo(int verbose
)
2380 unsigned long nbr_of_colors
= 1 << Pdepth
;
2382 fprintf(stderr
, "FVWM info on colors\n");
2383 fprintf(stderr
, " Visual ID: 0x%x, Default?: %s, Class: ",
2384 (int)(Pvisual
->visualid
),
2385 (Pdefault
)? "Yes":"No");
2386 if (Pvisual
->class == TrueColor
)
2388 fprintf(stderr
,"TrueColor");
2390 else if (Pvisual
->class == PseudoColor
)
2392 fprintf(stderr
,"PseudoColor");
2394 else if (Pvisual
->class == DirectColor
)
2396 fprintf(stderr
,"DirectColor");
2398 else if (Pvisual
->class == StaticColor
)
2400 fprintf(stderr
,"StaticColor");
2402 else if (Pvisual
->class == GrayScale
)
2404 fprintf(stderr
,"GrayScale");
2406 else if (Pvisual
->class == StaticGray
)
2408 fprintf(stderr
,"StaticGray");
2410 fprintf(stderr
, "\n");
2411 fprintf(stderr
, " Depth: %i, Number of colors: %lu",
2412 Pdepth
, (unsigned long)nbr_of_colors
);
2415 fprintf(stderr
,"\n Pallet with %i colors", PColorLimit
);
2416 if (Pvisual
->class & 1)
2418 fprintf(stderr
,", Number of free colors: %i\n",
2419 get_nbr_of_free_colors((1 << Pdepth
)));
2421 " Auto Detected: %s, Strict: %s, Allocated: %s,"
2423 (Pcsi
.pre_allocated_pallet
)? "Yes":"No",
2424 (PStrictColorLimit
)? "Yes":"No",
2425 (PAllocTable
)? "Yes":"No",
2426 (PUseDynamicColors
)? "Yes":"No");
2430 fprintf(stderr
," (default colormap)\n");
2432 if (PColorLimit
<= 256)
2436 int count_alloc
= 0;
2440 fprintf(stderr
," The fvwm colors table:\n");
2442 for (i
= 0; i
< PColorLimit
; i
++)
2448 " rgb:%.3i/%.3i/%.3i\t%lu\n",
2449 Pct
[i
].color
.red
>> 8,
2450 Pct
[i
].color
.green
>> 8,
2451 Pct
[i
].color
.blue
>> 8,
2452 Pct
[i
].alloc_count
);
2454 if (Pct
[i
].alloc_count
)
2459 if ((Pvisual
->class & 1) && Pac
!= NULL
)
2463 fprintf(stderr
," fvwm colors not in"
2466 for(i
=0; i
< nbr_of_colors
; i
++)
2471 if (!Pac
[i
].alloc_count
)
2473 while(j
< PColorLimit
&& !found
)
2475 if (i
== Pct
[j
].color
.pixel
)
2489 "%.3i/%.3i/%.3i\t%lu\n",
2490 Pac
[i
].color
.red
>> 8,
2491 Pac
[i
].color
.green
>> 8,
2492 Pac
[i
].color
.blue
>> 8,
2493 Pac
[i
].alloc_count
);
2496 if (verbose
&& count_alloc
== 0)
2500 fprintf(stderr
," None\n");
2504 if (Pvisual
->class & 1)
2507 " Number of colours used by fvwm:\n");
2509 " In the table: %i\n", count
);
2511 stderr
, " Out of the table: %i\n",
2514 " Total: %i\n", count_alloc
+count
);
2520 if (Pvisual
->class == DirectColor
)
2522 fprintf(stderr
, ", Pseudo Pallet with: %i colors\n",
2523 (1 << Pcsi
.red_prec
)*(1 << Pcsi
.green_prec
)*
2524 (1 << Pcsi
.blue_prec
));
2528 fprintf(stderr
, ", No Pallet (static colors)\n");
2530 fprintf(stderr
, " red: %i, green: %i, blue %i\n",
2531 1 << Pcsi
.red_prec
, 1 << Pcsi
.green_prec
,
2532 1 << Pcsi
.blue_prec
);
2533 if (verbose
&& Pdepth
<= 8)
2535 if (Pvisual
->class == DirectColor
)
2537 fprintf(stderr
, " Colormap:\n");
2542 " Static Colormap used by fvwm:\n");
2544 print_colormap(Pcmap
);
2548 if (Pdepth
<= 8 && verbose
>= 2)
2550 fprintf(stderr
,"\n Default Colormap:\n");
2551 print_colormap(DefaultColormap(Pdpy
,DefaultScreen(Pdpy
)));