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

Linux Cross Reference
Tina5/tina-tools/tinatool/gphx/gdk2/gphxGdk_cmap.c

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

  1 /**********
  2  * 
  3  * Copyright (c) 2003, Division of Imaging Science and Biomedical Engineering,
  4  * University of Manchester, UK.  All rights reserved.
  5  * 
  6  * Redistribution and use in source and binary forms, with or without modification, 
  7  * are permitted provided that the following conditions are met:
  8  * 
  9  *   . Redistributions of source code must retain the above copyright notice, 
 10  *     this list of conditions and the following disclaimer.
 11  *    
 12  *   . Redistributions in binary form must reproduce the above copyright notice,
 13  *     this list of conditions and the following disclaimer in the documentation 
 14  *     and/or other materials provided with the distribution.
 15  * 
 16  *   . Neither the name of the University of Manchester nor the names of its
 17  *     contributors may be used to endorse or promote products derived from this 
 18  *     software without specific prior written permission.
 19  * 
 20  * 
 21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  * POSSIBILITY OF SUCH DAMAGE.
 32  *
 33  **********
 34  * 
 35  * Program :  TINA
 36  * File    :  $Source: /home/tina/cvs/tina-tools/tinatool/gphx/gdk2/gphxGdk_cmap.c,v $
 37  * Date    :  $Date: 2005/06/01 20:06:25 $
 38  * Version :  $Revision: 1.1 $
 39  * CVS Id  :  $Id: gphxGdk_cmap.c,v 1.1 2005/06/01 20:06:25 paul Exp $
 40  *
 41  * Author  :  giob@man.ac.uk
 42  *
 43  *********
 44 */
 45 /** 
 46  *  @file  gphxGdk_cmap.c
 47  *  @brief Functions to define and handle colourmaps.
 48  *
 49  *  VERY different to X11.
 50  *
 51  *  In colourmap handling, GDK provides a choice - use the raw X11-style colourmaps or
 52  *  use GdkRGB.  The latter is intended as a simpler interface, but it brings its own 
 53  *  problems in that the representation of colours and colourmaps all has to be handled
 54  *  delicately with pointers and large arrays.
 55  *
 56  *  However, GdkRGB confers the advantage of substantial system independence.  For example,
 57  *  all colourmaps can be 256 colour, and as Tina was designed with this model this is an
 58  *  appropriate simplification of the colourmap handling.  Moreover, with GdkRGB all 
 59  *  colourmaps are effectively writeable.
 60  *
 61  *  The penalty for this simplicity is the representation of colours.  A GdkRGB colour is
 62  *  a 32-bit int with the bits assigned as follows:
 63  *  -  1st 8 bits unused;  
 64  *  -  2nd 8 bits red value (0-255);
 65  *  -  3rd 8 bits green value (0-255); 
 66  *  -  4th 8 bits blue value (0-255).
 67  *  Creating a GdkRGB colourmap (GdkRGBCmap) requires an array of 256 concatenated 32-bit 
 68  *  ints, representing the colours required in the map.  GdkRGB handles the rest (i.e. colour
 69  *  allocation, etc.).
 70  *
 71  *  So we gain some freedom in colour representation at the expense of some simple but finicky
 72  *  pointer arithmetic.  And of course we have to deal with byte-order issues.  All of that stuff 
 73  *  is done in this file.  
 74  *
 75  *  Note: the functions in this file are duplicated for each graphics lib (x11, GDK, etc ...).
 76  *
 77  */
 78 
 79 
 80 #include "gphxGdk_cmap.h"
 81 
 82 #if HAVE_CONFIG_H
 83   #include <config.h>
 84 #endif
 85 
 86 #include <gtk/gtk.h>
 87 #include <tinatool/draw/drawDef.h>
 88 #include <tinatool/draw/drawPro.h>
 89 #include <tinatool/gphx/gdk/gphx_GdkDef.h>
 90 
 91 #define CMAP_ARRAY_CREATE(_size) ((GdkColor *) ralloc((unsigned)(_size) * sizeof(GdkColor)))
 92 
 93 
 94 /**
 95  * @brief  If key matches data return data, else return NULL.  
 96  * @param  key   Pointer to Cmap_data for comparision.
 97  * @param  data  Pointer to Cmap_data to be compared to key.
 98  * @return void *   Void pointer to data or NULL.
 99  *
100  * Comparison on the basis of visual and colourmap only..
101  */
102 static void   *cmap_data_match(Cmap_data *key, Cmap_data *data)
103 {
104   void  *match_or_null;
105 
106   match_or_null = (key
107                    && data
108                    && data->visual         == key->visual
109                    && data->cmap_create_fn == key->cmap_create_fn
110                   )
111                   ? (void *) data : NULL; 
112 
113   return match_or_null;
114 }
115 
116 /**
117  * @brief  Initialise Cmap_data struct and create new colormap but don't fill it.  
118  * @param  cmap_data  Pointer to Cmap_data struct for which to create cmap.
119  *
120  * This function is much simplified compared to the X11 version.  GdkRGB always
121  * allows us to treat the visual as dynamic (even if it is not, GdkRGB hides that
122  * fact from us).  GdkRGB also allows us to always use 256 colours (Tina doesn't 
123  * need any more) with a depth (nplanes) of 8 bits and we do not need to keep a
124  * set of base colours to prevent colurmap flashing, GdkRGB handles that as well.
125  *
126  * So this function has been reduced to the setting of a few standardised values (see 
127  * (see gphx_GdkDef.h) and just a little error checking.
128  */
129 void   cmap_data_init(Cmap_data *cmap_data)
130 {
131   if (cmap_data)
132   {
133     GdkVisual *visual = cmap_data->visual;
134 
135     /* Set model & type */
136     /* All colourmaps are dynamic with GdkRgb. */
137     cmap_data->type  = cmap_type_dynamic;
138 
139     switch (visual->type)
140     {
141       case GDK_VISUAL_STATIC_COLOR:
142           cmap_data->model = cmap_model_col;
143           break;
144       case GDK_VISUAL_STATIC_GRAY:
145           cmap_data->model = cmap_model_gs;
146           break;
147       case GDK_VISUAL_TRUE_COLOR:
148           cmap_data->model = cmap_model_rgb;
149           break;
150       case GDK_VISUAL_DIRECT_COLOR:
151           cmap_data->model = cmap_model_rgb;
152           break;
153       case GDK_VISUAL_GRAYSCALE:
154           cmap_data->model = cmap_model_gs;
155           break;
156       case GDK_VISUAL_PSEUDO_COLOR:
157           cmap_data->model = cmap_model_col;
158           break;
159       default:
160           cmap_data->model = cmap_model_unknown;
161           cmap_data->type  = cmap_type_unknown;
162           break;
163     }
164 
165     if (cmap_data->type == cmap_type_unknown)
166     {
167           errorf(warning, "cmap_data_init: unknown visual type.\n");
168     }
169 
170     /** Set these mostly from gphx_GdkDef.h, as GdkRGB allows the use of standard values. */
171     cmap_data->ncells   = RGB_NCOLS;
172     cmap_data->base     = RGB_BASE;
173     cmap_data->nplanes  = RGB_NPLANES;
174     cmap_data->colormap = (GdkRgbCmap *) NULL;
175     cmap_data->rgbcols  = (guchar *) g_malloc0 (RGB_NCOLS * 4 * sizeof(guchar));
176   }
177 }
178 
179 /**
180  * @brief  Return a void pointer to the colourmap of cmap_data.  
181  * @param  cmap_data  Pointer to the Cmap_data struct for which to get the colourmap.
182  * @return void *   Void pointer to the colourmap of cmap_data.
183  */
184 void   *cmap_data_cmap_get(Cmap_data *cmap_data)
185 {
186   return (void *) (cmap_data ? cmap_data->colormap : NULL);
187 }
188 
189 /**
190  * @brief  Set the colourmap of cmap_data to cmap.  
191  * @param  cmap_data  Pointer to the Cmap_data struct for which to set the colourmap.
192  * @param  cmap       Pointer to the GdkRgbCmap to be set as the new colourmap.
193  */
194 void    cmap_data_cmap_set(Cmap_data *cmap_data, GdkRgbCmap *cmap)
195 {
196   if(cmap_data)
197     cmap_data->colormap = cmap;
198 }
199 
200 /**
201  * @brief  Get the number of cells in the colormap of cmap_data.  
202  * @param  cmap_data  Pointer to the Cmap_data struct for which to return the number of colours.
203  * @return int   Number of colours in cmap_data->colormap.
204  *
205  * OK, this is not really needed, as all colourmaps are now 256 colour.  However, it is needed
206  * for backward compatibility with X11 Tina, and to avoid changing code at higher levels.
207  */
208 int   cmap_data_cmap_ncells_get(Cmap_data *cmap_data)
209 {
210   return RGB_NCOLS;
211 }
212 
213 /**
214  * @brief  Find a Cmap_data appropriate for the given Tv, or create a new one.  
215  * @param  tv                   Pointer to current Tv.
216  * @param  tv_screen_cmap_data  Pointer to Cmap_data for which to find an equivalent.
217  * @param  ndefault_colors      What it says on the tin.
218  * @return Bool   True if found or false if not.
219  *
220  * The Cmap_data struct holds all the information required to use a colourmap (see
221  * gphx_GdkDef.h) and the colourmap itself, as well as a lookup table, overlay mask 
222  * and the colourmap create function.  To keep things neat, we build a list of all 
223  * Cmap_data structs (as they are created).  This function checks to see if an 
224  * appropriate Cmap_data struct exists in this list, and if not it creates one and
225  * adds it to the list.  In the process, the colourmap itself is created and filled.
226  */
227 Bool   cmap_data_find_or_create(Tv *tv, Cmap_data *tv_screen_cmap_data, int ndefault_colors)
228 {
229   Bool        cmap_ok   = true;
230   Cmap_data  *cmap_data = NULL;
231 
232   static List *cmap_database = NULL;   /* List of Cmap_data structs created so far. */
233   static int   old_colors    = -1;
234 
235   if (old_colors == -1) 
236     old_colors = ndefault_colors;
237 
238   if (tv && tv_screen_cmap_data)
239   {
240     /* 
241      * Search list for existing Cmap_data.  If one is found it is 
242      * assigned to cmap_data; if not, NULL is assigned.
243      */
244     cmap_data = (Cmap_data *) list_query(cmap_database, 
245                                          cmap_data_match,
246                                          (void *) tv_screen_cmap_data);
247 
248     /* 
249      * If we found a pre-existing Cmap_data we use it, otherwise we make a new one.
250      */
251     if (cmap_data && (old_colors == ndefault_colors))
252     {
253       tv->cmap_data_visible = (Cmap_data_visible *) cmap_data;
254     } 
255     else
256     {
257       /* Create blank Cmap_data and copy values from tv */
258        cmap_data = ts_ralloc(Cmap_data);
259       *cmap_data = *tv_screen_cmap_data;
260        tv->cmap_data_visible = (Cmap_data_visible *) cmap_data;
261 
262       /* cmap_create_fn creates cmap. Fills tv's cmap_data_visible */
263       if ((cmap_ok = tv->cmap_create_fn(tv, ndefault_colors)))
264       {
265         cmap_data = (Cmap_data *) tv->cmap_data_visible;
266         cmap_data->cmap_create_fn = tv->cmap_create_fn;
267         cmap_data->colormap = gdk_rgb_cmap_new((guint32 *)cmap_data->rgbcols, RGB_NCOLS);
268 
269         /* Add Cmap_data to our list */
270         cmap_database = ref_addtostart(cmap_database, (void *) cmap_data, 0);
271       }
272     }
273   }
274 
275   return cmap_ok;
276 }
277 
278 /**
279  * @brief  Find out the endian of the machine we are running on.  
280  * @return  0 if false, otherwise non-zero.
281  */
282 int   big_endian()
283 {
284   short   a = 0x0001;
285 
286   return (int)*((unsigned char*) (&a));
287 }
288 
289 /**
290  * @brief  Fill tina_colors (array) with 'ncolors' colors from the colourmap in cmap_data.  
291  * @param  cmap_data    Pointer to Cmap_data holding the colourmap from which to get colours.
292  * @param  tina_colors  Pointer to Tina_color array to be filled.
293  * @param  base         Number of default colours (not used).
294  * @param  ncolors      Number of colours to be filled.
295  *
296  * Base is not required in GTK/GDK Tina (it is always zero) but it has to be included for
297  * compatibility with X11 Tina.  The colour values get a left-shift becasue although GdkRGB
298  * expects char values (0-255) Tina_color holds short int values, and in drawTv_cmap.c these
299  * are assigned with a corresponding right shift.  We can't change this rather awkward 
300  * functionality without losing compatibility with X11 Tina.
301  */
302 void   cmap_query_colors(Cmap_data *cmap_data, Tina_color *tina_colors, int base, int ncolors)
303 {
304   int   i;
305 
306   for (i = 0; i < ncolors; i++) 
307   {
308     /* Pixel values stay raw but Tina_color values get a left shift for consistency */
309     /* (See drawTv_cmap.c) */
310     if (big_endian())
311     {
312       tina_colors[i].pixel = (Tina_pixel)     (cmap_data->rgbcols[4*i + 3]);
313       tina_colors[i].red   = (unsigned short) (cmap_data->rgbcols[4*i + 2] << 8);
314       tina_colors[i].green = (unsigned short) (cmap_data->rgbcols[4*i + 1] << 8);
315       tina_colors[i].blue  = (unsigned short) (cmap_data->rgbcols[4*i]     << 8);
316     }
317     else
318     {
319       tina_colors[i].pixel = (Tina_pixel)     (cmap_data->rgbcols[4*i]);
320       tina_colors[i].red   = (unsigned short) (cmap_data->rgbcols[4*i + 1] << 8);
321       tina_colors[i].green = (unsigned short) (cmap_data->rgbcols[4*i + 2] << 8);
322       tina_colors[i].blue  = (unsigned short) (cmap_data->rgbcols[4*i + 3] << 8);
323     }
324   }
325 }
326 
327 /**
328  * @brief  Fill the colourmap in cmap_data with 'ncolors' colors from the tina_colors (array).  
329  * @param  cmap_data    Pointer to Cmap_data holding the colourmap to which to add colours.
330  * @param  tina_colors  Pointer to Tina_color array holding the colours to be added.
331  * @param  base         Number of default colours (not used).
332  * @param  ncolors      Number of colours to be added.
333  *
334  * Here base is used because it represents the number of colours already added to the map, 
335  * rather than the number of default colours (cf. cmap_query_colors).
336  */
337 void   cmap_store_colors(Cmap_data *cmap_data, Tina_color *tina_colors, int base, int ncolors)
338 {
339   if (cmap_data && cmap_data->rgbcols)
340   {
341     int             i;
342 
343     /* Fill tina_colors array with pixels for each cell in cmap */
344     /* Index in tina_colors array is canonical position in cmap. */
345     if ((base + ncolors) <= RGB_NCOLS)
346     {
347 
348       for (i = 0; i < ncolors; i++)
349       {
350         int j = base + i;
351 
352         tina_colors[i].pixel  = (Tina_pixel) j;
353 
354         /** Pixel values stay raw but Tina_color values get a right shift for consistency */
355         /* (See drawTv_cmap.c) */
356         if (big_endian())
357         {
358           cmap_data->rgbcols[4*j + 3]  = (guchar) (j);
359           cmap_data->rgbcols[4*j + 2]  = (guchar) (tina_colors[i].red >> 8);
360           cmap_data->rgbcols[4*j + 1]  = (guchar) (tina_colors[i].green >> 8);
361           cmap_data->rgbcols[4*j]      = (guchar) (tina_colors[i].blue >> 8);
362         }
363         else
364         {
365           cmap_data->rgbcols[4*j]      = (guchar) (j);
366           cmap_data->rgbcols[4*j + 1]  = (guchar) (tina_colors[i].red >> 8);
367           cmap_data->rgbcols[4*j + 2]  = (guchar) (tina_colors[i].green >> 8);
368           cmap_data->rgbcols[4*j + 3]  = (guchar) (tina_colors[i].blue >> 8);
369         }
370       }
371 
372     }
373     else
374     {
375       errorf(warning, "%s\n %s\t\t%d\n %s\t%d\n %s\t%d\n %s\t%d\n",
376                       "cmap_store_colors: too many colors",
377                       "base", base,
378                       "ncolors", ncolors,
379                       "total colors", base + ncolors,
380                       "cells in cmap", cmap_data->visual->depth);
381     }
382   }
383 }
384 
385 /**
386  * @brief  Not used in practice so will not be implemented - GAB 15 Dec 200.  
387  */
388 void    named_colors_rgbs_get(Cmap_data * cmap_data, char **color_names, int ncolors, Rgb * rgbs)
389 {
390 /*
391  * Only called from cmap_data_named_color_fill, which itself is not called from anywhere.
392  * Not used in practice so will not be implemented - GAB 15 Dec 2003
393  */
394 }
395 
396 /**
397  * @brief  Create and initialise a Cmap_data struct for the given tv_screen.  
398  * @param  tv_screen_void   Void pointer to Tv_screen for which to create cmap_data.
399  * @param  ndefault_colors  Number of system colours to keep in the colourmap (not used).
400  * @return Cmap_data_visible *   Pointer to new Cmap_data_visible.
401  *
402  * Note that ndefault_colors is not used.  Its purpose in the X11 Tina was to minimise
403  * screen flashing when the system colourmap was swapped in and out on 8-bit systems.
404  * In GTK/GDK Tina this is not necessary because GdkRGB deals with the colourmap swapping
405  * and prevents flashing.
406  */
407 Cmap_data_visible   *tv_screen_cmap_create(void *tv_screen_void, int ndefault_colors)
408 {
409   Cmap_data  *cmap_data = NULL;
410   Tv_screen  *tv_screen = (Tv_screen *) tv_screen_void;
411 
412   if (tv_screen)
413   {
414     /* Fill in (window system specific) cmap_data */
415     cmap_data = ts_ralloc(Cmap_data);
416     cmap_data->visual = tv_screen->visual;
417 
418     /* Init this cmap_data struct */
419     cmap_data_init(cmap_data);
420   }
421 
422   return (Cmap_data_visible *) cmap_data;
423 }
424 
425 /**
426  * @brief  Find & install a colourmap on a tv_screen using a tv's colourmap create function.  
427  * @param  tv         Pointer to the Tv struct from which to use the colourmap create function.
428  * @param  tv_screen  Pointer to the Tv_screen struct for which to install a colourmap.
429  *
430  * Look for a colourmap created with the tv's cmap_create_fn and assign it to the tv_screen.
431  * If no such colourmap is found, create a new one using the tv's cmap_create_fn and assign
432  * that one instead.  Update the tv's cmap_data_visible struct.
433  */
434 void   tv_screen_cmap_find_and_install(Tv *tv, Tv_screen *tv_screen)
435 {
436   static int   old_ndefault=-1;
437   if (old_ndefault==-1) old_ndefault = ndefault_colors_get();
438 
439   if (tv_screen)
440   {
441     Cmap_data   tv_screen_cmap_data = {Cmap_data_id};
442     Cmap_data  *tv_cmap_data        = (Cmap_data *) tv->cmap_data_visible;
443 
444     /** Set visual for cmap_data of tv_screen */
445     tv_screen_cmap_data.visual = tv_screen->visual;
446 
447     /** Use tv's cmap_create_fn. */
448     tv_screen_cmap_data.cmap_create_fn = tv->cmap_create_fn;
449 
450     if (cmap_data_match(&tv_screen_cmap_data, tv_cmap_data)
451         && tv_cmap_data->colormap == tv_screen->colormap
452         && old_ndefault           == ndefault_colors_get()
453        )
454     {
455       /* Displays, visuals & colormaps match. Do nowt. */
456       return;
457     } 
458     else
459     {
460       /* If tv's cmap_create_fn is NULL use default, otherwise use tv's ... */
461       if (!tv->cmap_create_fn)
462       {
463         tv->cmap_create_fn = tv_standard_cmap_create;
464       }
465       tv_screen_cmap_data.cmap_create_fn = tv->cmap_create_fn;
466 
467       /* Find an existing colourmap or create a new one */
468       if (cmap_data_find_or_create(tv, &tv_screen_cmap_data, ndefault_colors_get()))
469       {
470         tv_screen_cmap_install(tv_screen,
471                                ((Cmap_data *) tv->cmap_data_visible)->colormap);
472       }
473     }
474   }
475 }
476 
477 /**
478  * @brief  Set the GdkRGB colourmap as the tv_screen's colormap, and install it.  
479  * @param  tv_screen  Pointer to Tv_screen for which to set colourmap.
480  * @param  cmap       GdkRGBCmap to be set as the Tv_screen colourmap.
481  *
482  * Note that cmap is NOT the colourmap installed to the window.  This is the colourmap
483  * used by GdkRGB, which is returned by gdk_rgb_get_cmap().
484  */
485 void   tv_screen_cmap_install(Tv_screen *tv_screen, GdkRgbCmap *cmap)
486 {
487   if (cmap != NULL)     
488     tv_screen->colormap = cmap;
489 
490   gdk_window_set_colormap(tv_screen->window, gdk_rgb_get_cmap());
491 }
492 
493 

~ [ 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.