1 /***********************************************************/
2 /* */
3 /* System dependent color management */
4 /* */
5 /***********************************************************/
6
7 #include "unix/guts.h"
8 #include "Drawable.h"
9 #include "Window.h"
10
11 /* have two color layouts for panel widgets (lists, edits) and gray widgets (buttons, labels) */
12 #define COLOR_DEFAULT_TEXT 0x000000
13 #define COLOR_DEFAULT_GRAY 0xcccccc
14 #define COLOR_DEFAULT_BACK 0xffffff
15
16 #define COLOR_GRAY_NORMAL_TEXT COLOR_DEFAULT_TEXT
17 #define COLOR_GRAY_NORMAL_BACK COLOR_DEFAULT_GRAY
18 #define COLOR_GRAY_HILITE_TEXT COLOR_DEFAULT_TEXT
19 #define COLOR_GRAY_HILITE_BACK COLOR_DEFAULT_GRAY
20 #define COLOR_GRAY_DISABLED_TEXT 0x606060
21 #define COLOR_GRAY_DISABLED_BACK 0xcccccc
22
23 #define COLOR_PANEL_NORMAL_TEXT COLOR_DEFAULT_TEXT
24 #define COLOR_PANEL_NORMAL_BACK COLOR_DEFAULT_BACK
25 #define COLOR_PANEL_HILITE_TEXT COLOR_DEFAULT_BACK
26 #define COLOR_PANEL_HILITE_BACK COLOR_DEFAULT_TEXT
27 #define COLOR_PANEL_DISABLED_TEXT 0x606060
28 #define COLOR_PANEL_DISABLED_BACK 0xdddddd
29
30 #define COLOR_LIGHT3D 0xffffff
31 #define COLOR_DARK3D 0x808080
32
33 #define COLORSET_GRAY_NORMAL COLOR_GRAY_NORMAL_TEXT, COLOR_GRAY_NORMAL_BACK
34 #define COLORSET_GRAY_HILITE COLOR_GRAY_HILITE_TEXT, COLOR_GRAY_HILITE_BACK
35 #define COLORSET_GRAY_ALT_HILITE COLOR_GRAY_HILITE_BACK, COLOR_GRAY_HILITE_TEXT
36 #define COLORSET_GRAY_DISABLED COLOR_GRAY_DISABLED_TEXT, COLOR_GRAY_DISABLED_BACK
37
38 #define COLORSET_PANEL_NORMAL COLOR_PANEL_NORMAL_TEXT, COLOR_PANEL_NORMAL_BACK
39 #define COLORSET_PANEL_HILITE COLOR_PANEL_HILITE_TEXT, COLOR_PANEL_HILITE_BACK
40 #define COLORSET_PANEL_DISABLED COLOR_PANEL_DISABLED_TEXT, COLOR_PANEL_DISABLED_BACK
41
42 #define COLORSET_3D COLOR_LIGHT3D, COLOR_DARK3D
43
44 #define COLORSET_GRAY COLORSET_GRAY_NORMAL, COLORSET_GRAY_HILITE, \
45 COLORSET_GRAY_DISABLED, COLORSET_3D
46 #define COLORSET_ALT_GRAY COLORSET_GRAY_NORMAL, COLORSET_GRAY_ALT_HILITE, \
47 COLORSET_GRAY_DISABLED, COLORSET_3D
48 #define COLORSET_PANEL COLORSET_PANEL_NORMAL, COLORSET_PANEL_HILITE, \
49 COLORSET_PANEL_DISABLED, COLORSET_3D
50
51 static Color standard_button_colors[] = { COLORSET_GRAY };
52 static Color standard_checkbox_colors[] = { COLORSET_GRAY };
53 static Color standard_combo_colors[] = { COLORSET_GRAY };
54 static Color standard_dialog_colors[] = { COLORSET_GRAY };
55 static Color standard_edit_colors[] = { COLORSET_PANEL };
56 static Color standard_inputline_colors[] = { COLORSET_PANEL };
57 static Color standard_label_colors[] = { COLORSET_GRAY };
58 static Color standard_listbox_colors[] = { COLORSET_PANEL };
59 static Color standard_menu_colors[] = { COLORSET_ALT_GRAY };
60 static Color standard_popup_colors[] = { COLORSET_ALT_GRAY };
61 static Color standard_radio_colors[] = { COLORSET_GRAY };
62 static Color standard_scrollbar_colors[] = { COLORSET_ALT_GRAY };
63 static Color standard_slider_colors[] = { COLORSET_GRAY };
64 static Color standard_widget_colors[] = { COLORSET_ALT_GRAY };
65 static Color standard_window_colors[] = { COLORSET_GRAY };
66 static Color standard_application_colors[] = { COLORSET_GRAY };
67
68 static Color* standard_colors[] = {
69 NULL,
70 standard_button_colors, /* Prima.Button.* */
71 standard_checkbox_colors, /* Prima.Checkbox.* */
72 standard_combo_colors, /* Prima.Combo.* */
73 standard_dialog_colors, /* Prima.Dialog.* */
74 standard_edit_colors, /* ...etc... */
75 standard_inputline_colors,
76 standard_label_colors,
77 standard_listbox_colors,
78 standard_menu_colors,
79 standard_popup_colors,
80 standard_radio_colors,
81 standard_scrollbar_colors,
82 standard_slider_colors,
83 standard_widget_colors,
84 standard_window_colors,
85 standard_application_colors,
86 };
87
88 static const int MAX_COLOR_CLASS = sizeof( standard_colors) / sizeof( standard_colors[ 0]) - 1;
89
90 Color **
prima_standard_colors(void)91 prima_standard_colors(void)
92 {
93 return standard_colors;
94 }
95
96 /* maps RGB or cl-constant value to RGB value. */
97 Color
prima_map_color(Color clr,int * hint)98 prima_map_color( Color clr, int * hint)
99 {
100 long cls;
101 if ( hint) *hint = COLORHINT_NONE;
102 if (( clr & clSysFlag) == 0) return clr;
103
104 cls = (clr & wcMask) >> 16;
105 if ( cls <= 0 || cls > MAX_COLOR_CLASS) cls = (wcWidget) >> 16;
106 if (( clr = ( clr & ~wcMask)) > clMaxSysColor) clr = clMaxSysColor;
107 if ( clr == clSet) {
108 if ( hint) *hint = COLORHINT_WHITE;
109 return 0xffffff;
110 } else if ( clr == clClear) {
111 if ( hint) *hint = COLORHINT_BLACK;
112 return 0;
113 } else if ( clr == clInvalid) {
114 return 0xffffff;
115 } else return standard_colors[cls][(clr & clSysMask) - 1];
116 }
117
118 Color
apc_widget_map_color(Handle self,Color color)119 apc_widget_map_color( Handle self, Color color)
120 {
121 if ((( color & clSysFlag) != 0) && (( color & wcMask) == 0)) color |= PWidget(self)-> widgetClass;
122 return prima_map_color( color, NULL);
123 }
124
125 static PHash hatches;
126 static Bool kill_hatches( Pixmap pixmap, int keyLen, void * key, void * dummy);
127 static Bool prima_color_new( XColor * xc);
128
129 /*
130 static int card[256];
131 static int cardi = 0;
132 static Bool
133 my_XAllocColor( Display * disp, Colormap cm, XColor * xc, int line)
134 {
135 if ( !cardi) {
136 cardi = 1;
137 bzero( card, 256*sizeof(int));
138 }
139 if ( !XAllocColor(disp, cm, xc)) {
140 printf("Failed alloc of %02x%02x%02x, at %d\n",
141 xc-> red>>8, xc-> green>>8, xc-> blue>>8, line);
142 return false;
143 }
144 printf("Alloc %02x%02x%02x, at %d: %d\n",
145 xc-> red>>8, xc-> green>>8, xc-> blue>>8,
146 line, xc-> pixel);
147 card[xc-> pixel]++;
148 return true;
149 }
150
151 static void
152 my_XFreeColors( Display * disp, Colormap cm, long * ls, int count, long pal, int line)
153 {
154 XSynchronize( DISP, true);
155 printf("Free at %d:%d items\n", line, count);
156 for ( pal = 0; pal < count; pal++, ls++) {
157 printf("%ld.", *ls);
158 XFreeColors( disp, cm, ls, 1, 0);
159 XSync( disp, false);
160 if ( !card[*ls]) printf("jopa!\n");
161 else card[*ls]--;
162 }
163 printf("done\n");
164 }
165
166 #define XAllocColor(a,b,c) my_XAllocColor(a,b,c,__LINE__)
167 #define XFreeColors(a,b,c,d,e) my_XFreeColors(a,b,c,d,e,__LINE__)
168 */
169
170 static Bool
alloc_color(XColor * c)171 alloc_color( XColor * c)
172 {
173 int diff = 5 * 256,
174 r = c-> red,
175 g = c-> green,
176 b = c-> blue;
177 if ( !XAllocColor( DISP, guts. defaultColormap, c)) return false;
178 if (
179 diff > abs( c-> red - r) &&
180 diff > abs( c-> green - g) &&
181 diff > abs( c-> blue - b)
182 ) return true;
183 XFreeColors( DISP, guts. defaultColormap, &c->pixel, 1, 0);
184 return false;
185 }
186
187 /*
188 Fills Brush structure. If dithering is needed,
189 brush.secondary and brush.balance are set. Tries to
190 get new colors via XAllocColor, assigns new color cells
191 to self if successfull.
192 If no brush structure is given, no dithering is
193 preformed.
194 Returns closest matching color, always the same as
195 brush-> primary.
196 */
197 unsigned long
prima_allocate_color(Handle self,Color color,Brush * brush)198 prima_allocate_color( Handle self, Color color, Brush * brush)
199 {
200 DEFXX;
201 Brush b;
202 int a[3], hint;
203
204 if ( !brush) brush = &b;
205 brush-> balance = 0;
206 brush-> color = color = prima_map_color( color, &hint);
207
208 if ( hint)
209 return ( brush-> primary = (( hint == COLORHINT_BLACK) ? LOGCOLOR_BLACK : LOGCOLOR_WHITE));
210
211 a[0] = COLOR_R(color);
212 a[1] = COLOR_G(color);
213 a[2] = COLOR_B(color);
214
215 if ( self && XF_LAYERED(XX) )
216 return brush->primary =
217 (((a[0] << guts. argb_bits. red_range ) >> 8) << guts. argb_bits. red_shift) |
218 (((a[1] << guts. argb_bits. green_range) >> 8) << guts. argb_bits. green_shift) |
219 (((a[2] << guts. argb_bits. blue_range ) >> 8) << guts. argb_bits. blue_shift);
220
221 if ( guts. grayScale) {
222 a[0] = a[1] = a[2] = ( a[0] + a[1] + a[2]) / 3;
223 color = a[0] * ( 65536 + 256 + 1);
224 }
225 Pdebug("color: %s asked for %06x\n", self?PWidget(self)->name:"null", color);
226 if (self && XT_IS_BITMAP(XX)) {
227 Byte balance = ( a[0] + a[1] + a[2] + 6) / (3 * 4);
228 if ( balance < 64) {
229 brush-> primary = 0;
230 brush-> secondary = 1;
231 brush-> balance = balance;
232 } else
233 brush-> primary = 1;
234 } else {
235 if ( guts. palSize > 0) {
236 int ab2;
237 Bool dyna = guts. dynamicColors && self && X(self)-> type. widget && ( self != application);
238 brush-> primary = prima_color_find( self, color, -1, &ab2, RANK_FREE);
239
240 if ( dyna && ab2 > 12) {
241 XColor xc;
242 xc. red = COLOR_R16(color);
243 xc. green = COLOR_G16(color);
244 xc. blue = COLOR_B16(color);
245 xc. flags = DoGreen | DoBlue | DoRed;
246 prima_color_sync();
247 if ( alloc_color( &xc)) {
248 prima_color_new( &xc);
249 Pdebug("color: %s alloc %d ( wanted %06x). got %02x %02x %02x\n", PWidget(self)-> name, xc.pixel, color, xc.red>>8,xc.green>>8,xc.blue>>8);
250 prima_color_add_ref( self, xc. pixel, RANK_NORMAL);
251 return brush-> primary = xc. pixel;
252 }
253 }
254
255 if ( guts. useDithering && (brush != &b) && (ab2 > 12)) {
256 if ( guts. grayScale && guts. systemColorMapSize > guts. palSize / 2) {
257 int clr = ( COLOR_R(color) + COLOR_G(color) +
258 COLOR_B(color)) / 3;
259 int grd = 256 / ( guts. systemColorMapSize - 1);
260 int left = clr / grd;
261 brush-> balance = ( clr - left * grd) * 64 / grd;
262 brush-> primary = guts. systemColorMap[ left];
263 brush-> secondary = guts. systemColorMap[ left + 1];
264 } else {
265 int i;
266 Bool cubic = (XX-> type.dbm && guts. dynamicColors) ||
267 ( guts. colorCubeRib > 4);
268 DITHER:
269 if ( cubic) {
270 /* fast search of dithering colors - based on color cube.
271 used either on restricted drawables ( as dbm) or when
272 have enough colors - small cubes give noisy picture
273
274 . . . *R"G" assume here that blue component does not require dithering
275 R | R'G' and R"G" are 2 colors blended with proprotion to make
276 | '''* A color A. R'G' is a closest cubic color. If A(G)/A(R) < y,
277 | | R"G" is G-point, if A(G)/A(R) > 1 + y, it's R-point, otherwise
278 *---------- G it's RG-point. (y=sqrt(2)-1=0.41; y=0.41x and y=1.41x are
279 R'G' , B=0 maximal error lines). balance is computed as diff between
280 R'G' and R"G"
281 */
282 int base[3], l[3], z[3], r[3], cnt = 0, sum = 0;
283 int grd = 256 / ( guts. colorCubeRib - 1);
284 for ( i = 0; i < 3; i++) {
285 base[i] = a[i] / grd;
286 r[i] = l[i] = ( a[i] >= base[i] + grd / 2) ? 1 : 0;
287 z[i] = l[i] ? (base[i] + 1) * grd - a[i]: a[i] - base[i] * grd;
288 }
289 if ( z[1] > 1) {
290 int ratio1 = 100 * z[0] / z[1];
291 int ratio2 = 100 * z[2] / z[1];
292 if ( ratio1 > 59) r[0] = r[0] ? 0 : 1;
293 if ( ratio2 > 59) r[2] = r[2] ? 0 : 1;
294 if ( ratio1 < 141 && ratio2 < 141) r[1] = r[1] ? 0 : 1;
295 } else if ( z[2] > 1) {
296 int ratio = 100 * z[0] / z[2];
297 if ( ratio > 59) r[0] = r[0] ? 0 : 1;
298 if ( ratio < 141) r[2] = r[2] ? 0 : 1;
299 } else if ( z[0] > 1) {
300 r[0] = r[0] ? 0 : 1;
301 }
302 for ( i = 0; i < 3; i++)
303 if ( r[i] != l[i]) {
304 sum += z[i];
305 cnt++;
306 }
307 brush-> primary = guts. systemColorMap[
308 l[2] + base[2] +
309 ( l[1] + base[1]) * guts.colorCubeRib +
310 ( l[0] + base[0]) * guts.colorCubeRib * guts.colorCubeRib];
311 brush-> secondary = guts. systemColorMap[
312 r[2] + base[2] +
313 ( r[1] + base[1]) * guts.colorCubeRib +
314 ( r[0] + base[0]) * guts.colorCubeRib * guts.colorCubeRib];
315 brush-> balance = cnt ? (sum / cnt) * 64 / grd : 0;
316 } else {
317 /* slow search for dithering counterpart color; takes long time
318 but gives closest possible colors.
319
320 A* A - color to be expressed by B and D
321 /| . B - closest color
322 / | . D - candidate color
323 / | . C - closest color that can be expressed using B and D
324 *---*-------* The objective is to find such D whose AC is minimal and
325 B C D CD>BD. ( CD = (AD*AD-AB*AB+BD*BD)/2BD, AC=sqrt(AD*AD-CD*CD))
326 */
327 int b[3], d[3], i;
328 int ab2, bd2, ac2, ad2;
329 float cd, bd, BMcd=0, BMbd=0;
330 int maxDiff = 16777216, bestMatch = -1;
331 int mincd = maxDiff;
332 b[0] = guts. palette[brush-> primary].r;
333 b[1] = guts. palette[brush-> primary].g;
334 b[2] = guts. palette[brush-> primary].b;
335 Pdebug("color:want %06x, closest is %06x\n", color, guts.palette[brush-> primary].composite);
336 ab2 = (a[0]-b[0])*(a[0]-b[0]) +
337 (a[1]-b[1])*(a[1]-b[1]) +
338 (a[2]-b[2])*(a[2]-b[2]);
339 for ( i = 0; i < guts.palSize; i++) {
340 if ( guts.palette[i].rank == RANK_FREE) continue;
341 d[0] = guts. palette[i].r;
342 d[1] = guts. palette[i].g;
343 d[2] = guts. palette[i].b;
344 Pdebug("color:tasting %06x\n", guts.palette[i].composite);
345 bd2 = (d[0]-b[0])*(d[0]-b[0]) +
346 (d[1]-b[1])*(d[1]-b[1]) +
347 (d[2]-b[2])*(d[2]-b[2]);
348 bd = sqrt( bd2);
349 if ( bd == 0) continue;
350 ad2 = (d[0]-a[0])*(d[0]-a[0]) +
351 (d[1]-a[1])*(d[1]-a[1]) +
352 (d[2]-a[2])*(d[2]-a[2]);
353 cd = ( ad2 - ab2 + bd2) / (2 * bd);
354 Pdebug("color:bd:%g,bd2:%d, ad2:%d, cd:%g\n", bd, bd2, ad2, cd);
355 if ( cd < bd) {
356 ac2 = ad2 - cd * cd;
357 Pdebug("color:ac2:%d\n", ac2);
358 if ( ac2 < maxDiff || (( ac2 < maxDiff + 12) && (cd < mincd))) {
359 maxDiff = ac2;
360 bestMatch = i;
361 BMcd = cd;
362 BMbd = bd;
363 mincd = cd;
364 if ( mincd < 42) goto ENOUGH;
365 }
366 }
367 }
368 ENOUGH:;
369 if ( !guts. grayScale && maxDiff > (64/(guts.colorCubeRib-1))) {
370 cubic = true;
371 goto DITHER;
372 }
373 brush-> secondary = bestMatch;
374 brush-> balance = 63 - BMcd * 64 / BMbd;
375 }
376 }
377 }
378
379 if ( dyna) {
380 if ( wlpal_get( self, brush-> primary) == RANK_FREE)
381 prima_color_add_ref( self, brush-> primary, RANK_NORMAL);
382 if (( brush-> balance > 0) &&
383 ( wlpal_get( self, brush->secondary) == RANK_FREE))
384 prima_color_add_ref( self, brush-> secondary, RANK_NORMAL);
385 }
386 } else
387 brush-> primary =
388 (((a[0] << guts. screen_bits. red_range ) >> 8) << guts. screen_bits. red_shift) |
389 (((a[1] << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
390 (((a[2] << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits. blue_shift);
391 }
392 return brush-> primary;
393 }
394
395
396 static Bool
alloc_main_color_range(XColor * xc,int count,int maxDiff)397 alloc_main_color_range( XColor * xc, int count, int maxDiff)
398 {
399 int idx;
400 Bool err = false;
401
402 if ( count > guts. palSize) return false;
403
404 for ( idx = 0; idx < count; idx++)
405 xc[idx]. pixel = 0xFFFFFFFF;
406
407 for ( idx = 0; idx < count; idx++) {
408 int R = xc[idx]. red;
409 int G = xc[idx]. green;
410 int B = xc[idx]. blue;
411 if ( !XAllocColor( DISP, guts. defaultColormap, &xc[idx])) {
412 err = true;
413 break;
414 }
415 if ( xc[idx]. pixel >= guts. palSize) {
416 warn("color index out of range returned from XAllocColor()\n");
417 return false;
418 }
419 if (( xc[idx]. blue / 256 - B / 256) * ( xc[idx]. blue / 256 - B / 256) +
420 ( xc[idx]. green / 256 - G / 256) * ( xc[idx]. green / 256 - G / 256) +
421 ( xc[idx]. red / 256 - R / 256) * ( xc[idx]. red / 256 - R / 256) >
422 maxDiff) {
423 err = true;
424 break;
425 }
426 }
427
428 if ( err) {
429 unsigned long cnt = 0, free[32];
430 for ( idx = 0; idx < count; idx++)
431 if ( xc[idx]. pixel != 0xFFFFFFFF) {
432 free[ cnt++] = xc[idx]. pixel;
433 if ( cnt == 32) {
434 XFreeColors( DISP, guts. defaultColormap, free, 32, 0);
435 cnt = 0;
436 }
437 }
438 if ( cnt > 0)
439 XFreeColors( DISP, guts. defaultColormap, free, cnt, 0);
440 return false;
441 }
442 return true;
443 }
444
445 static Bool
create_std_palettes(XColor * xc,int count)446 create_std_palettes( XColor * xc, int count)
447 {
448 int idx;
449 if ( !( guts. palette = malloc( sizeof( MainColorEntry) * guts. palSize)))
450 return false;
451 if ( !( guts. systemColorMap = malloc( sizeof( int) * count))) {
452 free( guts. palette);
453 guts. palette = NULL;
454 return false;
455 }
456 bzero( guts. palette, sizeof( MainColorEntry) * guts. palSize);
457
458 for ( idx = 0; idx < guts. palSize; idx++) {
459 guts. palette[ idx]. rank = RANK_FREE;
460 list_create( &guts. palette[idx]. users, 0, 16);
461 }
462
463 for ( idx = 0; idx < count; idx++) {
464 int pixel = xc[idx]. pixel;
465 guts. palette[ pixel]. r = xc[idx]. red / 256;
466 guts. palette[ pixel]. g = xc[idx]. green / 256;
467 guts. palette[ pixel]. b = xc[idx]. blue / 256;
468 guts. palette[ pixel]. composite = RGB_COMPOSITE(
469 guts. palette[ pixel]. r,
470 guts. palette[ pixel]. g,
471 guts. palette[ pixel]. b);
472 guts. palette[ pixel]. rank = RANK_IMMUTABLE;
473 guts. systemColorMap[ idx] = pixel;
474 }
475
476 guts. systemColorMapSize = count;
477
478 return true;
479 }
480
481 static void
fill_cubic(XColor * xc,int d)482 fill_cubic( XColor * xc, int d)
483 {
484 int b, g, r, d2 = d * d, frac = 65535 / ( d - 1);
485 for ( b = 0; b < d; b++) for ( g = 0; g < d; g++) for ( r = 0; r < d; r++) {
486 int idx = b + g * d + r * d2;
487 xc[idx]. blue = b * frac;
488 xc[idx]. green = g * frac;
489 xc[idx]. red = r * frac;
490 }
491 }
492
493 static char * do_visual = NULL;
494 static PList color_options = NULL;
495
496 static void
set_color_class(int class,char * option,char * value)497 set_color_class( int class, char * option, char * value)
498 {
499 if ( !value) {
500 warn("`%s' must be given a value -- skipped\n", option);
501 return;
502 }
503 if ( !color_options) color_options = plist_create( 8, 8);
504 if ( !color_options) return;
505 list_add( color_options, ( Handle) class);
506 list_add( color_options, ( Handle) duplicate_string(value));
507 }
508
509 static void
apply_color_class(int c_class,Color value)510 apply_color_class( int c_class, Color value)
511 {
512 int i;
513 Color ** t = standard_colors + 1;
514 for ( i = 1; i < MAX_COLOR_CLASS; i++, t++) (*t)[c_class] = value;
515 Mdebug("color: class %d=%06x\n", c_class, value);
516 }
517
518 /* find color bounds and test if they are contiguous */
519 Bool
prima_find_color_mask_range(unsigned long mask,unsigned int * shift,unsigned int * range)520 prima_find_color_mask_range( unsigned long mask, unsigned int * shift, unsigned int * range)
521 {
522 int i, from = 0, to = 0, stage = 0;
523 for ( i = 0; i < 32; i++) {
524 switch ( stage) {
525 case 0:
526 if (( mask & ( 1 << i)) != 0) {
527 from = i;
528 stage++;
529 }
530 break;
531 case 1:
532 if (( mask & ( 1 << i)) == 0) {
533 to = i;
534 stage++;
535 }
536 break;
537 case 2:
538 if (( mask & ( 1 << i)) != 0) {
539 warn( "panic: unsupported pixel representation (0x%08lx)", mask);
540 return false;
541 }
542 }
543 }
544 if ( to == 0) to = 32;
545 *shift = from;
546 *range = to - from;
547 return true;
548 }
549
550 Bool
prima_init_color_subsystem(char * error_buf)551 prima_init_color_subsystem(char * error_buf)
552 {
553 int id, count, mask = VisualScreenMask|VisualDepthMask|VisualIDMask;
554 XVisualInfo template, *list = NULL;
555
556 /* check if non-default depth is selected */
557 id = -1;
558 {
559 char * c, * end;
560 if (( c = do_visual) ||
561 apc_fetch_resource( "Prima", "", "Visual", "visual",
562 NULL_HANDLE, frString, &c)) {
563 id = strtol( c, &end, 0);
564 if ( *end) id = -1;
565 if ( c != do_visual) free( c);
566 template. visualid = id;
567 list = XGetVisualInfo( DISP, VisualIDMask, &template, &count);
568 if ( count <= 0) {
569 warn("warning: visual id '%s' is not found\n", c);
570 if ( list) XFree( list);
571 id = -1;
572 }
573 }
574 }
575 free( do_visual);
576 do_visual = NULL;
577
578 FALLBACK_TO_DEFAULT_VISUAL:
579 if ( id < 0) {
580 template. screen = SCREEN;
581 template. depth = guts. depth;
582 template. visualid = XVisualIDFromVisual( XDefaultVisual( DISP, SCREEN));
583
584 list = XGetVisualInfo( DISP, mask, &template, &count);
585 if ( count == 0) {
586 sprintf( error_buf, "panic: no visuals found");
587 return false;
588 }
589 }
590
591 guts. visual = list[0];
592 guts. visualClass = guts. visual.
593 #if defined(__cplusplus) || defined(c_plusplus)
594 c_class;
595 #else
596 class;
597 #endif
598 XFree( list);
599
600 if ( guts. depth > 11 && guts. visualClass != TrueColor && guts. visualClass != DirectColor) {/* XXX */
601 if ( id >= 0) {
602 warn("warning: visual 0x%x is unusable: cannot use %d bit depth for something not TrueColor or DirectColor\n", id, guts. depth);
603 id = -1;
604 goto FALLBACK_TO_DEFAULT_VISUAL;
605 } else
606 sprintf( error_buf, "panic: %d bit depth is not true color", guts. depth);
607 return false;
608 }
609
610
611 guts. useDithering = true;
612 guts. dynamicColors = false;
613 guts. grayScale = false;
614 guts. palSize = 1 << guts. depth;
615 guts. palette = NULL;
616 guts. systemColorMap = NULL;
617 guts. systemColorMapSize = 0;
618 guts. colorCubeRib = 0;
619
620 if ( id >= 0) {
621 guts. defaultColormap = XCreateColormap( DISP, guts. root, guts.visual.visual, AllocNone);
622 guts. privateColormap = 1;
623 } else
624 guts. defaultColormap = DefaultColormap( DISP, SCREEN);
625
626 guts. monochromeMap[0] = BlackPixel( DISP, SCREEN);
627 guts. monochromeMap[1] = WhitePixel( DISP, SCREEN);
628 switch ( guts. visualClass) {
629 case DirectColor:
630 case TrueColor:
631 guts. useDithering = false;
632 guts. palSize = 0;
633 break;
634
635 case PseudoColor:
636 {
637 int max;
638 XColor xc[216];
639 guts. dynamicColors = true;
640 if ( guts. privateColormap && guts. palSize > 26 ) {
641 if ( guts. palSize > 125) max = 6; else
642 if ( guts. palSize > 64) max = 5; else
643 if ( guts. palSize > 27) max = 4; else max = 3;
644 } else
645 max = 2;
646 fill_cubic( xc, max);
647 if ( !alloc_main_color_range( xc, max * max * max, 27))
648 goto BLACK_WHITE;
649 if ( !create_std_palettes( xc, max * max * max)) {
650 sprintf( error_buf, "No memory");
651 return false;
652 }
653 guts. colorCubeRib = max;
654 }
655 break;
656
657 case StaticColor:
658 {
659 int d = 6, cd = 1;
660 XColor xc[216];
661 while ( d > 1) {
662 if ( d * d * d <= guts. palSize) {
663 fill_cubic( xc, d);
664 if ( alloc_main_color_range( xc, d * d * d, cd * 3)) {
665 if ( !create_std_palettes( xc, d * d * d)) {
666 sprintf( error_buf, "No memory");
667 return false;
668 }
669 break;
670 }
671 }
672 d--;
673 cd += 2;
674 }
675 if ( !guts. palette) goto BLACK_WHITE;
676 if ( d < 2) goto BLACK_WHITE_ALLOCATED;
677 guts. colorCubeRib = d;
678 }
679 break;
680
681 case StaticGray:
682 case GrayScale:
683 {
684 XColor xc[256];
685 int maxSteps = ( guts. visualClass == GrayScale && !guts. privateColormap ) ? 5 : 8;
686 int wantSteps = ( maxSteps > guts. depth) ? guts. depth : maxSteps;
687 while ( wantSteps > 1) {
688 int i, shades = 1 << wantSteps, c = 0, ndiv = 65536 / (shades-1);
689 for ( i = 0; i < shades; i++) {
690 xc[i].red = xc[i]. green = xc[i]. blue = c;
691 if (( c += ndiv) > 65535) c = 65535;
692 }
693 if ( alloc_main_color_range( xc, shades, 768 / shades)) {
694 if ( !create_std_palettes( xc, shades)) {
695 sprintf( error_buf, "No memory");
696 return false;
697 }
698 break;
699 }
700 wantSteps--;
701 }
702 if ( !guts. palette) goto BLACK_WHITE;
703 if ( wantSteps < 1) goto BLACK_WHITE_ALLOCATED;
704 if ( wantSteps > 4) guts. useDithering = false;
705 guts. colorCubeRib = wantSteps;
706 guts. grayScale = true;
707 }
708 break;
709 default:
710 BLACK_WHITE:
711 {
712 XColor xc[2];
713 if ( guts. privateColormap) {
714 xc[0]. red = xc[0]. green = xc[0]. blue = 0;
715 xc[1]. red = xc[1]. green = xc[1]. blue = 0xffff;
716 XAllocColor( DISP, guts. defaultColormap, xc);
717 XAllocColor( DISP, guts. defaultColormap, xc + 1);
718 guts. monochromeMap[0] = xc[0].pixel;
719 guts. monochromeMap[1] = xc[1].pixel;
720 } else {
721 xc[0]. pixel = BlackPixel( DISP, SCREEN);
722 xc[1]. pixel = WhitePixel( DISP, SCREEN);
723 XQueryColors( DISP, guts. defaultColormap, xc, 2);
724 }
725 XCHECKPOINT;
726 if ( !alloc_main_color_range( xc, 2, 65536) ||
727 !create_std_palettes( xc, 2)) {
728 sprintf( error_buf, "panic: unable to initialize color system");
729 return false;
730 }
731 }
732 BLACK_WHITE_ALLOCATED:
733 guts. useDithering = true;
734 guts. grayScale = true;
735 guts. colorCubeRib = 1;
736 break;
737 }
738
739 if ( guts. palSize > 0 &&
740 (guts. visualClass == StaticColor ||
741 guts. visualClass == StaticGray)) {
742 int i;
743 XColor * xc;
744 MainColorEntry * p;
745 if ( !( xc = malloc( sizeof( XColor) * guts. palSize))) {
746 sprintf( error_buf, "No memory");
747 return false;
748 }
749 for ( i = 0; i < guts. palSize; i++) xc[i]. pixel = i;
750 XQueryColors( DISP, guts. defaultColormap, xc, guts. palSize);
751 XCHECKPOINT;
752 p = guts. palette;
753 for ( i = 0; i < guts. palSize; i++) {
754 p-> r = xc[i]. red / 256;
755 p-> g = xc[i]. green / 256;
756 p-> b = xc[i]. blue / 256;
757 p-> composite = RGB_COMPOSITE( p-> r, p-> g, p-> b);
758 if ( p-> rank == RANK_FREE) p-> rank = RANK_IMMUTABLE + 1;
759 p++;
760 }
761 free( xc);
762 }
763
764 if (( guts. ditherPatterns = malloc( sizeof( FillPattern) * 65))) {
765 int i, x, y;
766 FillPattern * p = guts. ditherPatterns;
767 Byte map [64] = {
768 0, 48, 12, 60, 3, 51, 15, 63,
769 32, 16, 44, 28, 35, 19, 47, 31,
770 8, 56, 4, 52, 11, 59, 7, 55,
771 40, 24, 36, 20, 43, 27, 39, 23,
772 2, 50, 14, 62, 1, 49, 13, 61,
773 34, 18, 46, 30, 33, 17, 45, 29,
774 10, 58, 6, 54, 9, 57, 5, 53,
775 42, 26, 38, 22, 41, 25, 37, 21
776 };
777 bzero( p, sizeof( FillPattern) * 65);
778 for ( i = 0; i < 65; i++, p++)
779 for ( y = 0; y < 8; y++)
780 for ( x = 0; x < 8; x++)
781 if ( i <= map[y * 8 + x])
782 (*p)[y] |= 1 << x;
783
784 } else {
785 sprintf( error_buf, "No memory");
786 return false;
787 }
788 if ( guts. palSize == 0) {
789 prima_find_color_mask_range( guts. visual. red_mask, &guts. screen_bits. red_shift, &guts. screen_bits. red_range);
790 prima_find_color_mask_range( guts. visual. green_mask, &guts. screen_bits. green_shift, &guts. screen_bits. green_range);
791 prima_find_color_mask_range( guts. visual. blue_mask, &guts. screen_bits. blue_shift, &guts. screen_bits. blue_range);
792 guts. screen_bits. red_mask = guts. visual. red_mask;
793 guts. screen_bits. green_mask = guts. visual. green_mask;
794 guts. screen_bits. blue_mask = guts. visual. blue_mask;
795 }
796 guts. localPalSize = guts. palSize / 4 + ((guts. palSize % 4) ? 1 : 0);
797 hatches = hash_create();
798
799 /* get XRDB colors */
800 {
801 Color c;
802 if ( apc_fetch_resource( "Prima", "", "Color", "color", NULL_HANDLE, frColor, &c))
803 apply_color_class( ciFore, c);
804 if ( apc_fetch_resource( "Prima", "", "Back", "backColor", NULL_HANDLE, frColor, &c))
805 apply_color_class( ciBack, c);
806 if ( apc_fetch_resource( "Prima", "", "HiliteColor", "hiliteColor", NULL_HANDLE, frColor, &c))
807 apply_color_class( ciHiliteText, c);
808 if ( apc_fetch_resource( "Prima", "", "HiliteBackColor", "hiliteBackColor", NULL_HANDLE, frColor, &c))
809 apply_color_class( ciHilite, c);
810 if ( apc_fetch_resource( "Prima", "", "DisabledColor", "disabledColor", NULL_HANDLE, frColor, &c))
811 apply_color_class( ciDisabledText, c);
812 if ( apc_fetch_resource( "Prima", "", "DisabledBackColor", "disabledBackColor", NULL_HANDLE, frColor, &c))
813 apply_color_class( ciDisabled, c);
814 if ( apc_fetch_resource( "Prima", "", "Light3DColor", "light3DColor", NULL_HANDLE, frColor, &c))
815 apply_color_class( ciLight3DColor, c);
816 if ( apc_fetch_resource( "Prima", "", "Dark3DColor", "dark3DColor", NULL_HANDLE, frColor, &c))
817 apply_color_class( ciDark3DColor, c);
818 }
819
820
821 /* parse user colors */
822 if ( color_options) {
823 int i, c_class;
824 char *value;
825 XColor xcolor;
826 for ( i = 0; i < color_options-> count; i+=2) {
827 c_class = (int) color_options-> items[i];
828 value = (char*) color_options-> items[i+1];
829 if ( XParseColor( DISP, DefaultColormap( DISP, SCREEN), value, &xcolor)) {
830 apply_color_class( c_class, ARGB(xcolor.red >> 8, xcolor.green >> 8, xcolor.blue >> 8));
831 } else {
832 warn("Cannot parse color value `%s`", value);
833 }
834 free( value);
835 }
836 plist_destroy( color_options);
837 }
838
839 return true;
840 }
841
842 Bool
prima_color_subsystem_set_option(char * option,char * value)843 prima_color_subsystem_set_option( char * option, char * value)
844 {
845 if ( strcmp( option, "visual") == 0) {
846 if ( value) {
847 free( do_visual);
848 do_visual = duplicate_string( value);
849 Mdebug( "set visual: %s\n", do_visual);
850 } else
851 warn("`--visual' must be given value");
852 return true;
853 } else if ( strcmp( option, "fg") == 0) {
854 set_color_class( ciFore, option, value);
855 } else if ( strcmp( option, "bg") == 0) {
856 set_color_class( ciBack, option, value);
857 } else if ( strcmp( option, "hilite-bg") == 0) {
858 set_color_class( ciHilite, option, value);
859 } else if ( strcmp( option, "hilite-fg") == 0) {
860 set_color_class( ciHiliteText, option, value);
861 } else if ( strcmp( option, "disabled-bg") == 0) {
862 set_color_class( ciDisabled, option, value);
863 } else if ( strcmp( option, "disabled-fg") == 0) {
864 set_color_class( ciDisabledText, option, value);
865 } else if ( strcmp( option, "light") == 0) {
866 set_color_class( ciLight3DColor, option, value);
867 } else if ( strcmp( option, "dark") == 0) {
868 set_color_class( ciDark3DColor, option, value);
869 }
870 return false;
871 }
872
873 typedef struct
874 {
875 int count;
876 unsigned long free[256];
877 } FreeColorsStruct;
878
879 void
prima_done_color_subsystem(void)880 prima_done_color_subsystem( void)
881 {
882 int i;
883 FreeColorsStruct fc;
884
885 if ( DISP) {
886 hash_first_that( hatches, (void*)kill_hatches, NULL, NULL, NULL);
887 fc. count = 0;
888
889 for ( i = 0; i < guts. palSize; i++) {
890 list_destroy( &guts. palette[i]. users);
891 if (
892 !guts. privateColormap &&
893 guts. palette[i]. rank > RANK_FREE &&
894 guts. palette[i]. rank <= RANK_IMMUTABLE) {
895 fc. free[ fc. count++] = i;
896 if ( fc. count == 256) {
897 XFreeColors( DISP, guts. defaultColormap, fc. free, 256, 0);
898 fc. count = 0;
899 }
900 }
901 }
902 if ( fc. count > 0)
903 XFreeColors( DISP, guts. defaultColormap, fc. free, fc. count, 0);
904 XFreeColormap( DISP, guts. defaultColormap);
905 }
906
907 hash_destroy( hatches, false);
908 guts. defaultColormap = 0;
909 free( guts. ditherPatterns);
910 free( guts. palette);
911 free( guts. systemColorMap);
912 guts. palette = NULL;
913 guts. systemColorMap = NULL;
914 guts. ditherPatterns = NULL;
915 }
916
917 /*
918 Finds closest possible color in system palette.
919 Colors can be selectively filtered using maxRank
920 parameter - if it is greater that RANK_FREE, the colors
921 with rank lower that maxRank are not matched. Ranking can
922 make sense when self != NULL and self != application, and
923 of course when color cell manipulation is possible. In other
924 words, local palette is never used if maxRank > RANK_FREE.
925 maxDiff tells the maximal difference for a color. If
926 no color is found that is closer than maxDiff, -1 is returned
927 and pointer to actual diff is returned.
928 */
929 int
prima_color_find(Handle self,long color,int maxDiff,int * diff,int maxRank)930 prima_color_find( Handle self, long color, int maxDiff, int * diff, int maxRank)
931 {
932 int i, j, ret = -1;
933 int global;
934 int b = color & 0xff;
935 int g = (color >> 8) & 0xff;
936 int r = (color >> 16) & 0xff;
937 int lossy = maxDiff != 0;
938 if ( maxDiff < 0) maxDiff = 256 * 256 * 3;
939 global = self ? (X(self)-> type. widget && ( self != application)) : true;
940
941 maxDiff++;
942 if ( global || !guts. dynamicColors || (maxRank > RANK_FREE)) {
943 for ( i = 0; i < guts. palSize; i++) {
944 if ( guts. palette[i]. rank > maxRank) {
945 if ( lossy) {
946 int d =
947 ( b - guts. palette[i].b) * ( b - guts. palette[i].b) +
948 ( g - guts. palette[i].g) * ( g - guts. palette[i].g) +
949 ( r - guts. palette[i].r) * ( r - guts. palette[i].r);
950 if ( d < maxDiff) {
951 ret = i;
952 maxDiff = d;
953 if ( maxDiff == 0) break;
954 }
955 } else {
956 if ( color == guts. palette[i]. composite) {
957 ret = i;
958 break;
959 }
960 }
961 }
962 }
963 } else {
964 for ( j = 0; j < guts. systemColorMapSize + guts. palSize; j++) {
965 if ( j < guts. systemColorMapSize)
966 i = guts. systemColorMap[j];
967 else {
968 i = j - guts. systemColorMapSize;
969 if ( wlpal_get( self, i) == RANK_FREE) continue;
970 }
971 if ( lossy) {
972 int d =
973 ( b - guts. palette[i].b) * ( b - guts. palette[i].b) +
974 ( g - guts. palette[i].g) * ( g - guts. palette[i].g) +
975 ( r - guts. palette[i].r) * ( r - guts. palette[i].r);
976 if ( d < maxDiff) {
977 ret = i;
978 maxDiff = d;
979 if ( maxDiff == 0) break;
980 }
981 } else {
982 if ( color == guts. palette[i]. composite) {
983 ret = i;
984 break;
985 }
986 }
987 }
988 }
989 if ( diff) *diff = maxDiff;
990 return ret;
991 }
992
993 static Bool
prima_color_new(XColor * xc)994 prima_color_new( XColor * xc)
995 {
996 MainColorEntry * p = guts. palette + xc-> pixel;
997 if ( p-> rank != RANK_FREE) {
998 XFreeColors( DISP, guts. defaultColormap, &xc-> pixel, 1, 0);
999 return false;
1000 }
1001 p-> r = xc-> red >> 8;
1002 p-> g = xc-> green >> 8;
1003 p-> b = xc-> blue >> 8;
1004 p-> composite = RGB_COMPOSITE(p->r,p->g,p->b);
1005 return true;
1006 }
1007
1008 /*
1009 Adds reference to widget that is responsible
1010 for a color cell with given rank. Main palette
1011 rank can be risen in response, but not lowered -
1012 that is accomplished by prima_color_sync.
1013 */
1014 Bool
prima_color_add_ref(Handle self,int index,int rank)1015 prima_color_add_ref( Handle self, int index, int rank)
1016 {
1017 int r, nr = (rank == RANK_PRIORITY) ? 2 : 1;
1018 if ( index < 0 || index >= guts. palSize) return false;
1019 if ( guts. palette[index]. rank == RANK_IMMUTABLE) return false;
1020 if ( !self || ( self == application)) return false;
1021 r = wlpal_get(self, index);
1022 if ( r != 0 && r <= nr) return false;
1023 if ( r == 0) list_add( &guts. palette[index]. users, self);
1024 if ( rank > guts. palette[index]. rank)
1025 guts. palette[index]. rank = rank;
1026 wlpal_set( self, index, nr);
1027 Pdebug("color:%s %s %d %d\n", PWidget(self)-> name, r ? "raised to " : "added as", nr, index);
1028 return true;
1029 }
1030
1031 /* Frees stale color references */
1032 int
prima_color_sync(void)1033 prima_color_sync( void)
1034 {
1035 int i, count = 0, freed = 0;
1036 unsigned long free[32];
1037 MainColorEntry * p = guts. palette;
1038 for ( i = 0; i < guts. palSize; i++, p++) {
1039 if ( p-> touched) {
1040 int j, max = RANK_FREE;
1041 for ( j = 0; j < p-> users. count; j++) {
1042 int rank;
1043 if ( X(p-> users. items[j])-> type. widget) {
1044 rank = wlpal_get( p-> users. items[j], i);
1045 if ( rank > 0)
1046 rank = ( rank > 1) ? RANK_PRIORITY : RANK_NORMAL;
1047 } else
1048 rank = RANK_LOCKED;
1049 if ( max < rank) max = rank;
1050 if ( max == RANK_LOCKED) break;
1051 }
1052 p-> rank = max;
1053 if ( max == RANK_FREE) {
1054 free[ count++] = i;
1055 if ( count == 32) {
1056 XFreeColors( DISP, guts. defaultColormap, free, 32, 0);
1057 count = 0;
1058 freed += 32;
1059 }
1060 }
1061 p-> touched = false;
1062 }
1063 }
1064 if ( count > 0)
1065 XFreeColors( DISP, guts. defaultColormap, free, count, 0);
1066 return freed + count;
1067 }
1068
1069 /* updates contents of DefaultColormap. */
1070 /* NB - never to be called with 'fast' set to true. */
1071
1072 Bool
prima_palette_replace(Handle self,Bool fast)1073 prima_palette_replace( Handle self, Bool fast)
1074 {
1075 DEFXX;
1076 Bool restricted = fast || XX-> type. dbm;
1077 int rank, psz, i, j, granted, stage, menu = 0;
1078 unsigned long * req;
1079 RGBColor * rqx;
1080 MainColorEntry * p;
1081 List widgets;
1082
1083 if ( !guts. dynamicColors) return true;
1084 if ( self == application) return true;
1085
1086 if ( XX-> type.widget) rank = RANK_PRIORITY; else
1087 if ( XX-> type.image || XX-> type. dbm) rank = RANK_LOCKED; else
1088 return false;
1089
1090 if ( !fast) prima_palette_free( self, true); /* remove old entries */
1091
1092 psz = PDrawable( self)-> palSize + menu;
1093 if ( XT_IS_WINDOW(X(self)) && PWindow(self)-> menu)
1094 psz += (menu = ciMaxId + 1);
1095 if ( psz == 0) {
1096 prima_color_sync();
1097 return true;
1098 }
1099
1100 if ( !( req = malloc( sizeof( unsigned long) * psz)))
1101 return false;
1102
1103 for ( i = 0; i < psz - menu; i++)
1104 req[i] = RGB_COMPOSITE(
1105 PWidget( self)-> palette[i].r,
1106 PWidget( self)-> palette[i].g,
1107 PWidget( self)-> palette[i].b);
1108 for ( i = psz - menu; i < psz; i++)
1109 req[i] = PWindow(self)-> menuColor[ i - psz + menu];
1110
1111 granted = 0;
1112
1113 if ( !restricted) XGrabServer( DISP);
1114
1115 /* fetch actual colors - they are useful when no free colorcells
1116 available, but colormap has some good colors, which we don't
1117 possess */
1118 if ( !restricted) {
1119 int count = 0, j;
1120 XColor xc[32];
1121 for ( i = 0; i < guts.palSize; i++)
1122 if ( guts.palette[i].rank == RANK_FREE) {
1123 xc[count++].pixel = i;
1124 if ( count == 32) {
1125 XQueryColors( DISP, guts. defaultColormap, xc, 32);
1126 for ( j = 0; j < 32; j++) prima_color_new( &xc[j]);
1127 count = 0;
1128 }
1129 }
1130 if ( count > 0) {
1131 XQueryColors( DISP, guts. defaultColormap, xc, count);
1132 for ( j = 0; j < count; j++) prima_color_new( &xc[j]);
1133 }
1134 }
1135
1136 Pdebug("color replace:%s find match for %d colors\n", PWidget(self)-> name, psz);
1137 /* find out if any allocated entries are present already */
1138 for ( i = 0; i < psz; i++)
1139 if (( req[i] & 0x80000000) == 0) {
1140 unsigned long c = req[i];
1141 for ( j = 0; j < guts. palSize; j++) {
1142 MainColorEntry * p = guts. palette + j;
1143 int pixel = j;
1144 if ( p-> composite == c) {
1145 if ( !restricted && (p-> rank == RANK_FREE)) {
1146 XColor xc;
1147 xc. red = COLOR_R16(req[i]);
1148 xc. green = COLOR_G16(req[i]);
1149 xc. blue = COLOR_B16(req[i]);
1150 if ( alloc_color(&xc)) {
1151 if ( prima_color_new( &xc))
1152 /* to protect from sync - give actual status on SUCCESS */
1153 guts.palette[xc.pixel].rank = RANK_IMMUTABLE + 1;
1154 pixel = xc.pixel;
1155 } else
1156 continue;
1157 }
1158 req[i] |= 0x80000000;
1159 if ( !restricted) prima_color_add_ref( self, pixel, rank);
1160 granted++;
1161 break;
1162 }
1163 }
1164 }
1165
1166 Pdebug("color replace: granted %d\n", granted);
1167 if ( restricted) {
1168 free( req);
1169 return true;
1170 }
1171
1172
1173 stage = RANK_NORMAL;
1174 list_create( &widgets, 32, 128);
1175 if ( granted == psz) {
1176 free( req);
1177 goto SUCCESS;
1178 }
1179
1180 ALLOC_STAGE:
1181 /* allocate some colors */
1182 prima_color_sync();
1183 XCHECKPOINT;
1184 for ( i = 0; i < psz; i++)
1185 if (( req[i] & 0x80000000) == 0) {
1186 XColor xc;
1187 xc. red = COLOR_R16(req[i]);
1188 xc. green = COLOR_G16(req[i]);
1189 xc. blue = COLOR_B16(req[i]);
1190 if ( alloc_color( &xc)) {
1191 prima_color_new( &xc);
1192 prima_color_add_ref( self, xc. pixel, rank);
1193 granted++;
1194 req[i] |= 0x80000000;
1195 } else
1196 break;
1197 }
1198 Pdebug("color replace :ok - now %d are granted\n", granted);
1199
1200 if ( granted == psz) {
1201 free( req);
1202 goto SUCCESS;
1203 }
1204
1205 if ( stage == RANK_NORMAL) {
1206 /* try to remove RANK_NORMAL colors */
1207 p = guts. palette;
1208 for ( i = 0; i < guts. palSize; i++, p++) {
1209 if ( p-> rank == RANK_NORMAL) {
1210 int j;
1211 for ( j = 0; j < p-> users. count; j++) {
1212 Handle wij = p-> users. items[j];
1213 if ( list_index_of( &widgets, wij) < 0)
1214 list_add( &widgets, wij);
1215 if ( wlpal_get(wij, i) == RANK_NORMAL)
1216 wlpal_set( wij, i, RANK_FREE);
1217 }
1218 list_delete_all( &p-> users, false);
1219 p-> touched = true;
1220 stage = RANK_PRIORITY;
1221 }
1222 }
1223 if ( stage == RANK_PRIORITY) goto ALLOC_STAGE;
1224 }
1225
1226 free( req);
1227
1228 if ( XX-> type. image) goto SUCCESS;
1229
1230 /* try to remove RANK_PRIORITY entries */
1231 p = guts. palette;
1232 for ( i = 0; i < guts. palSize; i++, p++) {
1233 if ( p-> rank == RANK_PRIORITY) {
1234 int j;
1235 for ( j = 0; j < p-> users. count; j++) {
1236 Handle wij = p-> users. items[j];
1237 if ( X(wij)-> type. widget && list_index_of( &widgets, wij) < 0)
1238 list_add( &widgets, wij);
1239 wlpal_set( wij, i, RANK_FREE);
1240 }
1241 list_delete_all( &p-> users, false);
1242 p-> touched = true;
1243 }
1244 }
1245
1246 psz = prima_color_sync();
1247 if ( psz == 0) goto SUCCESS; /* free no RANK_PRIORITY colors :( */
1248 XCHECKPOINT;
1249
1250 /* collect big palette */
1251 j = 0;
1252 for ( i = 0; i < guts. palSize; i++)
1253 if ( guts. palette[i]. rank != RANK_FREE)
1254 j++;
1255 stage = j; /* immutable and locked colors */
1256 for ( i = 0; i < widgets. count; i++) {
1257 j += PWidget( widgets. items[i])-> palSize;
1258 if ( XT_IS_WINDOW(X(widgets. items[i])) &&
1259 PWindow(widgets. items[i])-> menu)
1260 j += ciMaxId + 1;
1261 }
1262
1263 Pdebug("color: BIG:%d vs %d\n", j, psz);
1264 if ( !( rqx = malloc( sizeof( RGBColor) * j))) goto SUCCESS; /* :O */
1265
1266 {
1267 RGBColor * r = rqx;
1268 for ( i = 0; i < guts. palSize; i++)
1269 if ( guts. palette[i]. rank != RANK_FREE) {
1270 r-> r = guts. palette[i]. r;
1271 r-> g = guts. palette[i]. g;
1272 r-> b = guts. palette[i]. b;
1273 r++;
1274 }
1275 for ( i = 0; i < widgets. count; i++) {
1276 memcpy( r, PWidget( widgets. items[i])-> palette,
1277 PWidget( widgets. items[i])-> palSize * sizeof( RGBColor));
1278 r += PWidget( widgets. items[i])-> palSize;
1279 if ( XT_IS_WINDOW(X(widgets. items[i])) &&
1280 PWindow(widgets. items[i])-> menu) {
1281 int k;
1282 for ( k = 0; k <= ciMaxId; k++, r++) {
1283 r-> r = COLOR_R(PWindow(widgets. items[i])-> menuColor[k]);
1284 r-> g = COLOR_G(PWindow(widgets. items[i])-> menuColor[k]);
1285 r-> b = COLOR_B(PWindow(widgets. items[i])-> menuColor[k]);
1286 }
1287 }
1288 }
1289 }
1290
1291 /* squeeze palette */
1292 if ( j > psz + stage) {
1293 int k, tolerance = 0, t2 = 0, lim = psz + stage;
1294 while ( 1) {
1295 for ( i = 0; i < j; i++) {
1296 RGBColor r = rqx[i];
1297 for ( k = (( i + 1) > stage) ? i + 1 : stage; k < j; ) {
1298 if (
1299 ( r.r - rqx[k].r) * ( r.r - rqx[k].r) +
1300 ( r.g - rqx[k].g) * ( r.g - rqx[k].g) +
1301 ( r.b - rqx[k].b) * ( r.b - rqx[k].b)
1302 <= t2) {
1303 if ( k < j - 1) rqx[k] = rqx[j-1];
1304 if ( --j <= lim) goto ENOUGH;
1305 } else
1306 k++;
1307 }
1308 }
1309 tolerance += 2;
1310 t2 = tolerance * tolerance;
1311 }
1312 ENOUGH:;
1313 }
1314
1315 Pdebug("color replace: ok. XAllocColor again\n");
1316 granted = 0;
1317 for ( i = stage; i < stage + psz; i++) {
1318 XColor xc;
1319 xc. red = rqx[i]. r << 8;
1320 xc. green = rqx[i]. g << 8;
1321 xc. blue = rqx[i]. b << 8;
1322 if ( alloc_color( &xc)) {
1323 if ( prima_color_new( &xc)) {
1324 /* give new color NORMAL status - to be cleaned automatically */
1325 /* upon 1st sync() invocation */
1326 guts. palette[xc. pixel]. touched = 1;
1327 guts. palette[xc. pixel]. rank = RANK_NORMAL;
1328 granted++;
1329 }
1330 } else
1331 break;
1332 }
1333 free( rqx);
1334 Pdebug("color replace: ok - %d out of %d \n", granted, psz);
1335 XCHECKPOINT;
1336
1337 /* now give away colors that can be mapped to reduced palette */
1338 prima_palette_replace( self, true);
1339 for ( i = 0; i < widgets. count; i++)
1340 prima_palette_replace( widgets. items[i], true);
1341 XCHECKPOINT;
1342
1343 SUCCESS:
1344
1345 /* restore status of pre-fetched colors */
1346 for ( i = 0; i < guts. palSize; i++)
1347 if ( guts.palette[i].rank == RANK_IMMUTABLE + 1)
1348 guts.palette[i].rank = RANK_PRIORITY;
1349
1350 prima_color_sync();
1351
1352 XUngrabServer( DISP);
1353
1354 for ( i = 0; i < widgets. count; i++)
1355 if ( PWidget( widgets. items[i])-> stage < csDead)
1356 apc_widget_invalidate_rect( widgets. items[i], NULL);
1357
1358 Pdebug("color replace: exit\n");
1359 list_destroy( &widgets);
1360 return true;
1361 }
1362
1363 Bool
prima_palette_alloc(Handle self)1364 prima_palette_alloc( Handle self)
1365 {
1366 if ( !guts. dynamicColors) return true;
1367 if ( !( X(self)-> palette = malloc( guts. localPalSize)))
1368 return false;
1369 bzero( X(self)-> palette, guts. localPalSize);
1370 return true;
1371 }
1372
1373 void
prima_palette_free(Handle self,Bool priority)1374 prima_palette_free( Handle self, Bool priority)
1375 {
1376 int i, max = priority ? 2 : 1;
1377 if ( !guts. dynamicColors) return;
1378 for ( i = 0; i < guts. palSize; i++) {
1379 int rank = wlpal_get(self,i);
1380 if ( rank > RANK_FREE && max >= rank) {
1381 wlpal_set( self, i, RANK_FREE);
1382 list_delete( &guts. palette[i]. users, self);
1383 Pdebug("color: %s free %d, %d\n", PWidget(self)-> name, i, rank);
1384 guts. palette[i]. touched = true;
1385 }
1386 }
1387 Pdebug(":%s for %s\n", priority ? "PRIO" : "", PWidget(self)-> name);
1388 }
1389
1390 int
prima_lpal_get(Byte * palette,int index)1391 prima_lpal_get( Byte * palette, int index)
1392 {
1393 return LPAL_GET( index, palette[ LPAL_ADDR( index ) ]);
1394 }
1395
1396 void
prima_lpal_set(Byte * palette,int index,int rank)1397 prima_lpal_set( Byte * palette, int index, int rank )
1398 {
1399 palette[ LPAL_ADDR( index ) ] &=~ LPAL_MASK( index);
1400 palette[ LPAL_ADDR( index ) ] |= LPAL_SET( index, rank);
1401 }
1402
1403
kill_hatches(Pixmap pixmap,int keyLen,void * key,void * dummy)1404 static Bool kill_hatches( Pixmap pixmap, int keyLen, void * key, void * dummy)
1405 {
1406 XFreePixmap( DISP, pixmap);
1407 return false;
1408 }
1409
1410 Pixmap
prima_get_hatch(FillPattern * fp)1411 prima_get_hatch( FillPattern * fp)
1412 {
1413 int i;
1414 Pixmap p;
1415 FillPattern fprev;
1416 Byte *mirrored_bits;
1417 if ( memcmp( fp, fillPatterns[fpSolid], sizeof( FillPattern)) == 0)
1418 return NULL_HANDLE;
1419 if (( p = ( Pixmap) hash_fetch( hatches, fp, sizeof( FillPattern))))
1420 return p;
1421
1422 mirrored_bits = ( guts.bit_order == MSBFirst) ? NULL : prima_mirror_bits();
1423 for ( i = 0; i < sizeof( FillPattern); i++) {
1424 fprev[i] = (*fp)[ sizeof(FillPattern) - i - 1];
1425 if ( guts.bit_order != MSBFirst) fprev[i] = mirrored_bits[fprev[i]];
1426 }
1427 if (( p = XCreateBitmapFromData( DISP, guts. root, (char*)fprev, 8, 8)) == None) {
1428 hash_first_that( hatches, (void*)kill_hatches, NULL, NULL, NULL);
1429 hash_destroy( hatches, false);
1430 hatches = hash_create();
1431 if (( p = XCreateBitmapFromData( DISP, guts. root, (char*)fprev, 8, 8)) == None)
1432 return NULL_HANDLE;
1433 }
1434 hash_store( hatches, fp, sizeof( FillPattern), ( void*) p);
1435 return p;
1436 }
1437