~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Tina4/src/X11/cmap.c

Version: ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /** @(#)Tina colormap handling (X11 version).
  2 **/
  3 
  4 /* Handle creation of colormaps & their installation in a window.
  5  * 
  6  * A colormap behaves like a lookup table indexed by pixel value and
  7  * giving rgb values. In X, it is a resource specific to the particular
  8  * display, screen and visual of the windows using it.
  9  * 
 10  * We create  a usable colormap in 2 stages: 1. create an empty colormap
 11  * with the function cmap_create, 2. fill in the rgb values for each
 12  * pixel value with the tv's cmap_create_fn function. The stardard one
 13  * is tv_standard_cmap_create, which copies some colours from the
 14  * screen's default colormap, and provides a range of colours, greys
 15  * and and overlay plane.
 16  * 
 17  * tv_screen_cmap_find_and_install: is called when a tv is installed on a
 18  * tv_screen. The 1st time the tv is installed it has no colormap
 19  * (((Cmap_data*)tv->cmap_data_visible)->colormap = None).  In this
 20  * case a new colormap is found or created and installed in the
 21  * tv_screen's window.
 22  * 
 23  * If the tv is being reinstalled AND its colormap is the same as the
 24  * tv_screen's colormap, (and the colormap's display, screen & visual
 25  * match those of the tv_screen) then the tv_screen's colormap is used
 26  * as is.  THIS IS THE NORM.
 27  * 
 28  * If the tv & tv_screen have different colormaps, then a 'database' of
 29  * previously created colormap's is searched for one that has the same
 30  * display, screen & visual as the tv AND was created by the tv's
 31  * cmap_create_fn.
 32  * 
 33  * If NOT found in the  database, the colormap is created using the tv's
 34  * cmap_create_fn (or, if this is NULL by a default function) for the
 35  * same display, screen & visual as the tv_screen's window.  The new
 36  * colormap is stored in the database.
 37  * 
 38  * We cannot simply carry around a colormap with the tv and install it in
 39  * the tv_screen's window because the tv may be installed on a
 40  * tv_screen with a different display, screen or visual. */
 41 
 42 #include <tina/tv.h>
 43 #include <tina/tvfuncs.h>
 44 #include <tina/sysfuncs.h>
 45 #include <tina/tv_screen.h>
 46 #include <tina/X11funcs.h>
 47 
 48 #define CMAP_ARRAY_CREATE(_size) ((XColor *) ralloc((unsigned)(_size) * sizeof (XColor)))
 49 
 50 /* FORWARD REFS */
 51 static void *cmap_data_match(Cmap_data * key, Cmap_data * data);
 52 static unsigned long cmap_rgb_mult(Visual * visual);
 53 static unsigned long lowest_bit_set(long unsigned int number);
 54 
 55 /* STATICS */
 56 
 57 /* Create new colormap. (display, screen & visual are in cmap_data.) */
 58 void    cmap_create(Cmap_data * cmap_data)
 59 {
 60     Colormap cmap = (Colormap) None;
 61 
 62     if (cmap_data)
 63     {
 64         Visual *visual = cmap_data->visual;
 65         Window  window =
 66         RootWindow(cmap_data->display, cmap_data->screen);
 67 
 68         /* Set model & type */
 69         switch (visual->class)
 70         {
 71         case StaticColor:
 72             cmap_data->model = cmap_model_col;
 73             cmap_data->type = cmap_type_static;
 74             break;
 75         case StaticGray:
 76             cmap_data->model = cmap_model_gs;
 77             cmap_data->type = cmap_type_static;
 78             break;
 79         case TrueColor:
 80             cmap_data->model = cmap_model_rgb;
 81             cmap_data->type = cmap_type_static;
 82             break;
 83         case DirectColor:
 84             cmap_data->model = cmap_model_rgb;
 85             cmap_data->type = cmap_type_dynamic;
 86             break;
 87         case GrayScale:
 88             cmap_data->model = cmap_model_gs;
 89             cmap_data->type = cmap_type_dynamic;
 90             break;
 91         case PseudoColor:
 92             cmap_data->model = cmap_model_col;
 93             cmap_data->type = cmap_type_dynamic;
 94             break;
 95         default:
 96             cmap_data->model = cmap_model_unknown;
 97             cmap_data->type = cmap_type_unknown;
 98             break;
 99         }
100 
101         /* Create colormap */
102         switch (cmap_data->type)
103         {
104             /* Can't set rgb's */
105         case cmap_type_static:
106             cmap = XCreateColormap(cmap_data->display, window, visual, AllocNone);
107             break;
108         case cmap_type_dynamic:
109             cmap = XCreateColormap(cmap_data->display, window, visual, AllocAll);
110             cmap_data->ncells = cmap_data->visual->map_entries;
111             break;
112         case cmap_type_unknown:
113         default:
114             cmap = DefaultColormap(cmap_data->display, cmap_data->screen);
115             errorf(warning, "cmap_create: unknown visual class: %d\n",
116                    cmap_data->type);
117             break;
118         }
119         cmap_data->nplanes = XDisplayPlanes(cmap_data->display, cmap_data->screen);
120 
121         /* These fields are filled in when cmap filled
122          * 
123          * cmap_data->base
124          * 
125          * cmap_data->std_lut[]
126          * 
127          * cmap_data->overlay_mask
128          * 
129          * cmap_data->color_lut */
130 
131         cmap_data->color_bits = 2 << cmap_data->nplanes;
132 
133         cmap_data->colormap = cmap;
134     }
135 }
136 
137 /* Get the colormap from cmap_data. */
138 void   *cmap_data_cmap_get(Cmap_data * cmap_data)
139 {
140     return (void *) (cmap_data ? cmap_data->colormap : None);
141 }
142 
143 /* Set the colormap from cmap_data. */
144 void    cmap_data_cmap_set(Cmap_data * cmap_data, Colormap cmap)
145 {
146     if (cmap_data)
147     {
148         cmap_data->colormap = cmap;
149     }
150 }
151 
152 /* Get the number of cells in the colormap from cmap_data. Only cannot
153    be trusted with the current version of X11 for 16 bit
154    colormaps so use default */
155 int     cmap_data_cmap_ncells_get(Cmap_data * cmap_data)
156 {
157     if (cmap_data->type == cmap_type_dynamic)
158        return cmap_data ? DisplayCells(cmap_data->display, cmap_data->screen) : 0;
159     else
160 /*
161        return cmap_data ? DisplayCells(cmap_data->display, cmap_data->screen) : 0;
162 */
163        return(256);
164 }
165 
166 /* Find a colormap for given display,screen & visual, created with
167  * cmap_create_fn. If found in database use that else create one and
168  * add it to database. */
169 Bool    cmap_data_find(Tv * tv, Cmap_data * tv_screen_cmap_data, int ndefault_colors)
170 {
171     Bool    cmap_ok = true;
172     Cmap_data *cmap_data = NULL;
173     static List *cmap_database = NULL;
174     static int old_colors =-1;
175     if (old_colors==-1) old_colors = ndefault_colors;
176 
177     if (tv && tv_screen_cmap_data)
178     {
179 
180         /* Search database for suitable colormap. */
181         cmap_data = (Cmap_data *) list_query(cmap_database, cmap_data_match,
182                                         (void *) tv_screen_cmap_data);
183 
184         if (cmap_data&&(old_colors==ndefault_colors))
185         {
186             tv->cmap_data_visible = (Cmap_data_visible *) cmap_data;
187         } else
188         {
189 
190             /* Create colormap, copy some values from tv & store all in
191              * database */
192             cmap_data = ts_ralloc(Cmap_data);
193             *cmap_data = *tv_screen_cmap_data;
194             tv->cmap_data_visible = (Cmap_data_visible *) cmap_data;
195 
196             /* cmap_create_fn creates cmap. Fills tv's
197              * cmap_data_visible */
198             if ((cmap_ok = tv->cmap_create_fn(tv, ndefault_colors)))
199             {
200                 cmap_data = (Cmap_data *) tv->cmap_data_visible;
201                 cmap_data->cmap_create_fn = tv->cmap_create_fn;
202 
203                 /* Add data to database */
204                 cmap_database = ref_addtostart(cmap_database, (void *) cmap_data, 0);
205             }
206         }
207     }
208     return cmap_ok;
209 }
210 
211 /* Copy 'ncolors' colors from source colormap (starting at source_base)
212  * to destination colormap  (starting at dest_base). */
213 void    cmap_copy_colors(Cmap_data_visible * source_cmap_data,
214                          int source_base, Cmap_data_visible * dest_cmap_data,
215                          int dest_base, int ncolors)
216 {
217     Tina_color *tina_colors = NULL;
218 
219     /* Copy to dynamic visual classes only */
220     switch (dest_cmap_data->type)
221     {
222     case cmap_type_static:
223         /* Static visual classes, can't set rgb's */
224         format("cmap_copy_colors: can't copy to cmap of static visual class\n");
225         break;
226 
227     case cmap_type_dynamic:
228         /* Dynamic visual classes */
229         /* Copy 'ncolors' rgb's from source_base in  source to
230          * rgb_array */
231         tina_colors = TINA_COLOR_ARRAY_CREATE(ncolors);
232         (void) cmap_query_colors((Cmap_data *)source_cmap_data, tina_colors, source_base,
233                                  ncolors);
234         (void) cmap_store_colors((Cmap_data *)dest_cmap_data, tina_colors, dest_base, ncolors);
235         rfree((void *) tina_colors);
236         break;
237 
238         /* Unknown visual class */
239     default:
240         format("cmap_copy_colors: unknown visual class\n");
241         break;
242     }
243 }
244 
245 /* Fill colormap (from cell 0) with 'ndefault_colors' colors from
246  * default colormap. Sets cmap_data->base to ndefault_colors. */
247 void    cmap_data_default_color_fill(Cmap_data * cmap_data, int ndefault_colors)
248 {
249     if (cmap_data && cmap_data->visual)
250     {
251 
252         /* Fill rgb_array with 1st 'ndefault_colors' colors in default
253          * colormap */
254         Cmap_data default_cmap_data = {Cmap_data_id};
255 
256         default_cmap_data = *cmap_data;
257         default_cmap_data.colormap = DefaultColormap(cmap_data->display,
258                                                    cmap_data->screen);
259         default_cmap_data.visual = DefaultVisual(cmap_data->display,
260                                                  cmap_data->screen);
261         cmap_copy_colors((Cmap_data_visible *) & default_cmap_data, 0,
262                          (Cmap_data_visible *) cmap_data, 0,
263                          ndefault_colors);
264         cmap_data->base = ndefault_colors;
265     }
266 }
267 
268 /* Compare key & data.  If they match return data else return NULL. */
269 static void *cmap_data_match(Cmap_data * key, Cmap_data * data)
270 {
271     return (key &&
272             data &&
273             data->display == key->display &&
274             data->screen == key->screen &&
275             data->visual == key->visual &&
276             data->cmap_create_fn == key->cmap_create_fn
277     ) ? (void *) data : NULL;
278 }
279 
280 /* Fill tina_colors (array) with 'ncolors' colors (X pixel & rgb's
281  * (range: 0 - 0XFFFF)) starting at 'base' in colormap. */
282 void    cmap_query_colors(Cmap_data * cmap_data, Tina_color * tina_colors, int base,
283                                   int ncolors)
284 /* pixel & rgb fields to fill. */
285 {
286     int     i,j;
287     unsigned long rgb_mult = cmap_rgb_mult(cmap_data->visual);
288     XColor *cmap_array = CMAP_ARRAY_CREATE(ncolors);
289     if (cmap_data&&cmap_data->type != cmap_type_static)
290     {
291 
292         for (i = 0; i < ncolors; i++)
293         {
294 
295             /* Fill rgb_array with pixels for each cell in cmap */
296             cmap_array[i].pixel = (base + i) * rgb_mult;
297         }
298     }
299     else if (cmap_data &&cmap_data->type == cmap_type_static)
300     {
301         int pixel=-1,j;
302         for (i = 0, j=0; j <  CMAPLOOKUPNUMBEROFGREYS; j++ )
303         {
304             if (i == ncolors) break;  
305             if ( (cmap_array[i].pixel = cmap_data->std_lut[CMAPLOOKUPGREYSBASE + j ])
306                    != pixel )  
307             {
308                 pixel = cmap_array[i++].pixel;
309             }
310         }
311         for (j=0; j <  CMAPLOOKUPNUMBEROFCOLORS; j++ )
312         {
313             if (i == ncolors) break;  
314             if ( (cmap_array[i].pixel = cmap_data->std_lut[CMAPLOOKUPCOLORSBASE + j ]) 
315                    != pixel )
316             {
317                 pixel = cmap_array[i++].pixel;
318             }
319         }
320     }
321     for (i = 0; i < ncolors; i++) 
322     {
323         XQueryColor(cmap_data->display, cmap_data->colormap, &cmap_array[i]);
324         tina_colors[i].pixel = cmap_array[i].pixel;
325         tina_colors[i].red = cmap_array[i].red;
326         tina_colors[i].green = cmap_array[i].green;
327         tina_colors[i].blue = cmap_array[i].blue;
328     }
329 
330     rfree((void *) cmap_array);
331 
332 }
333 
334 /* Find the multiplier which gives the next cell in a cmap.  Eg in a 24
335  * bit DirectColor visual rgb_mult is 0x010101 */
336 static unsigned long cmap_rgb_mult(Visual * visual)
337 {
338     unsigned long rgb_mult = 1;
339 
340     if (visual)
341     {
342         rgb_mult =
343             (lowest_bit_set(visual->red_mask) |
344              lowest_bit_set(visual->green_mask) |
345              lowest_bit_set(visual->blue_mask));
346     }
347     return rgb_mult;
348 }
349 
350 /* Fill colormap (starting at 'base') with 'ncolors' colors (rgb's in
351  * tina_colors array). NB calculates pixels from index in array, offset
352  * by base.  Sets 'tina_colors[].pixel' to XColor pixel of colormap
353  * cells used. */
354 void    cmap_store_colors(Cmap_data * cmap_data, Tina_color * tina_colors, int base, int ncolors)
355 
356 /* Uses rgb fields & fills in pixel field */
357 
358 {
359     if (cmap_data && cmap_data->colormap)
360     {
361         int     i;
362         unsigned long rgb_mult = cmap_rgb_mult(cmap_data->visual);
363 
364         /* Fill tina_colors array with pixels for each cell in cmap */
365 
366         /* Index in tina_colors array is cannonical position in cmap. */
367         if ((base + ncolors) <= 256)
368         {
369             XColor *cmap_array = CMAP_ARRAY_CREATE(ncolors);
370 
371             for (i = 0; i < ncolors; i++)
372             {
373                 tina_colors[i].pixel = (base + i) * rgb_mult;
374                 cmap_array[i].pixel = tina_colors[i].pixel;
375                 cmap_array[i].red = tina_colors[i].red;
376                 cmap_array[i].green = tina_colors[i].green;
377                 cmap_array[i].blue = tina_colors[i].blue;
378                 cmap_array[i].flags = DoRed | DoGreen | DoBlue;
379                    
380             }
381             if (cmap_data->type == cmap_type_dynamic)
382                XStoreColors(cmap_data->display, cmap_data->colormap, cmap_array,
383                             ncolors);
384             else
385             {
386                for (i=0 ; i < ncolors; i++)
387                {
388                   XAllocColor(cmap_data->display,
389                               cmap_data->colormap,&cmap_array[i]); 
390                   tina_colors[i].pixel = cmap_array[i].pixel;
391                }
392             }
393             rfree((void *) cmap_array);
394 
395         } else
396         {
397             errorf(warning, "%s\n %s\t\t%d\n %s\t%d\n %s\t%d\n %s\t%d\n",
398                    "cmap_store_colors: too many colors",
399                    "base", base,
400                    "ncolors", ncolors,
401                    "total colors", base + ncolors,
402                    "cells in cmap", cmap_data->visual->map_entries);
403         }
404     }
405 }
406 
407 /* Find the lowest set bit in an unsigned long, return as mask.  Eg 12
408  * returns 4. */
409 static unsigned long lowest_bit_set(long unsigned int number)
410 {
411     unsigned long lowest = 1;
412 
413     if (number)
414     {
415         for (lowest = 1; !(number & lowest); lowest <<= 1);
416     }
417     return lowest;
418 }
419 
420 /* Get rgb's corresponding to named colors. */
421 void    named_colors_rgbs_get(Cmap_data * cmap_data, char **color_names, int ncolors, Rgb * rgbs)
422 {
423     if (cmap_data && cmap_data->display)
424     {
425         int     i;
426         XColor *cmap_array = CMAP_ARRAY_CREATE(ncolors);
427 
428         /* Fill cmap_array using color_names looked up in X data base */
429         for (i = 0; i < ncolors; i++)
430         {
431             Display *display = cmap_data->display;
432             Colormap cmap = cmap_data->colormap;
433 
434             /* 2nd argument merely used to determine screen */
435             if (!XParseColor(display, cmap, color_names[i],
436                              &(cmap_array[i])))
437             {
438                 XParseColor(display, cmap, "black",
439                             &(cmap_array[i]));
440             }
441             rgbs[i].red = cmap_array[i].red;
442             rgbs[i].green = cmap_array[i].green;
443             rgbs[i].blue = cmap_array[i].blue;
444         }
445         rfree((void *) cmap_array);
446     }
447 }
448 
449 /* Create colormap of the highest available model class:
450  * (DirectColor>PseudoColor>GrayScale). Also allocate & fill
451  * corresponding Cmap_data structure. If the color map is PseudoColor
452  * or GrayScale then the first ndefault_colors values in the color map
453  * are copied from some default values to prevent too much flashing as
454  * the colormap is (un)installed by the window manager. */
455 Cmap_data_visible *tv_screen_cmap_create(void *tv_screen_void, int ndefault_colors)
456 {
457     Cmap_data *cmap_data = NULL;
458     Tv_screen *tv_screen = (Tv_screen *) tv_screen_void;
459 
460     if (tv_screen)
461     {
462 
463         /* Create colormap & fill in (window system specific) cmap_data */
464         cmap_data = ts_ralloc(Cmap_data);
465         cmap_data->display = tv_screen->display;
466         cmap_data->screen = tv_screen->screen;
467         cmap_data->visual = tv_screen->visual;
468         cmap_create(cmap_data);
469         if (cmap_data->type == cmap_type_dynamic)
470         {
471             (void) cmap_data_default_color_fill(cmap_data, ndefault_colors);
472         }
473     }
474     return (Cmap_data_visible *) cmap_data;
475 }
476 
477 /* Find & install a colormap in a tv_screen using a tv's
478  * cmap_create_fn. If colormaps of tv_screen & tv match do nowt.  Else
479  * find a colormap created with the tv's cmap_create_fn and install it
480  * in the tv_screen's window and update the tv's cmap_data_visible
481  * structure.  Finding a colormap means either retrieving a suitable
482  * one from a database or creating a new one and storing in the
483  * database. */
484 void    tv_screen_cmap_find_and_install(Tv * tv, Tv_screen * tv_screen)
485 {
486     static int old_ndefault=-1;
487     if (old_ndefault==-1) old_ndefault = ndefault_colors_get();
488     if (tv_screen)
489     {
490         Cmap_data tv_screen_cmap_data = {Cmap_data_id};
491         Cmap_data *tv_cmap_data = (Cmap_data *) tv->cmap_data_visible;
492 
493         /* Compare cmap_data of Tv_screen & tv */
494         tv_screen_cmap_data.display = tv_screen->display;
495         tv_screen_cmap_data.screen = tv_screen->screen;
496         tv_screen_cmap_data.visual = tv_screen->visual;
497 
498         /* Use tv's cmap_create_fn. */
499         tv_screen_cmap_data.cmap_create_fn = tv->cmap_create_fn;
500 
501         if (cmap_data_match(&tv_screen_cmap_data, tv_cmap_data) &&
502             tv_cmap_data->colormap == tv_screen->colormap &&
503             old_ndefault == ndefault_colors_get())
504         {
505 
506             /* Displays, screens, visuals & colormaps match. Do nowt. */
507         } else
508         {
509 
510             /* Find a colormap  */
511 
512             /* If tv's cmap_create_fn is NULL use default. */
513             if (!tv->cmap_create_fn)
514             {
515                 tv->cmap_create_fn = tv_standard_cmap_create;
516             }
517             tv_screen_cmap_data.cmap_create_fn = tv->cmap_create_fn;
518 
519             /* Find a  colormap for both tv & tv_screen */
520             if (cmap_data_find(tv, &tv_screen_cmap_data,
521                                ndefault_colors_get()))
522             {
523                 tv_screen_cmap_install(tv_screen,
524                      ((Cmap_data *) tv->cmap_data_visible)->colormap);
525             }
526         }
527     }
528 }
529 
530 /* Install tv_screen's colormap as THE colormap.  Ie override window
531  * manager and use the tv_screen's colormap. (Window manager fails to
532  * do this.) */
533 void    tv_screen_cmap_install(Tv_screen * tv_screen, Colormap cmap)
534 {
535 
536     if (cmap == None)           /* just get color map to be installed */
537         cmap = tv_screen->colormap;
538     else
539     {
540         tv_screen->colormap = cmap;
541     }
542     XSetWindowColormap(tv_screen->display, tv_screen->window, cmap);
543     XInstallColormap(tv_screen->display, cmap);
544 }
545 
546 /* Get the number of cells in the colormap of a tv_screen. */
547 /*
548 int     tv_screen_cmap_ncells_get(Tv_screen * tv_screen)
549 {
550     int     ncells = 0;
551 
552     if (tv_screen)
553     {
554         ncells = tv_screen->visual->map_entries;
555     }
556     return ncells;
557 }
558 */
559 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.