Actual source code: xcolor.c

  1: /*$Id: xcolor.c,v 1.72 2001/03/23 23:20:15 balay Exp $*/

  3: /*
  4:     Code for managing color the X implementation of the PetscDraw routines.

  6:     Currently we default to using cmapping[0 to PETSC_DRAW_BASIC_COLORS-1] for the basic colors and 
  7:   cmapping[DRAW_BASIC_COLORS to 255] for a uniform hue of all the colors. But in the contour
  8:   plot we only use from PETSC_DRAW_BASIC_COLORS to 240 since the ones beyond that are too dark.

 10: */
 11:  #include src/sys/src/draw/impls/x/ximpl.h
 12: #include <X11/Xatom.h>

 14: static char *(colornames[PETSC_DRAW_BASIC_COLORS]) = { "white",
 15:                                                  "black",
 16:                                                  "red",
 17:                                                  "green",
 18:                                                  "cyan",
 19:                                                  "blue",
 20:                                                  "magenta",
 21:                                                  "aquamarine",
 22:                                                  "forestgreen",
 23:                                                  "orange",
 24:                                                  "violet",
 25:                                                  "brown",
 26:                                                  "pink",
 27:                                                  "coral",
 28:                                                  "gray",
 29:                                                  "yellow",
 30:                                                  "gold",
 31:                                                  "lightpink",
 32:                                                  "mediumturquoise",
 33:                                                  "khaki",
 34:                                                  "dimgray",
 35:                                                  "yellowgreen",
 36:                                                  "skyblue",
 37:                                                  "darkgreen",
 38:                                                  "navyblue",
 39:                                                  "sandybrown",
 40:                                                  "cadetblue",
 41:                                                  "powderblue",
 42:                                                  "deeppink",
 43:                                                  "thistle",
 44:                                                  "limegreen",
 45:                                                  "lavenderblush",
 46:                                                  "plum"};

 48: EXTERN int XiInitCmap(PetscDraw_X*);
 49: EXTERN int XiGetVisualClass(PetscDraw_X *);

 51: /*
 52:    Sets up a color map for a display. This is shared by all the windows
 53:   opened on that display; this is to save time when windows are open so 
 54:   each one does not have to create its own color map which can take 15 to 20 seconds

 56:      This is new code written 2/26/1999 Barry Smith,I hope it can replace
 57:   some older,rather confusing code.

 59:      The calls to XAllocNamedColor() and XAllocColor() are very slow 
 60:      because we have to request from the X server for each
 61:      color. Could not figure out a way to request a large number at the
 62:      same time.

 64:    IMPORTANT: this code will fail if user opens windows on two different 
 65:   displays: should add error checking to detect this. This is because all windows
 66:   share the same gColormap and gCmapping.

 68: */
 69: static Colormap  gColormap  = 0;
 70: static PixVal    gCmapping[256];
 71:        int       gNumcolors = 0;

 73: int PetscDrawSetUpColormap_Shared(Display *display,int screen,Visual *visual,Colormap colormap)
 74: {
 75:   XColor        colordef,ecolordef;
 76:   unsigned char *red,*green,*blue;
 77:   int           i,ierr,ncolors;
 78:   PetscTruth    fast;

 81:   if (colormap) {
 82:     gColormap = colormap;
 83:   } else {
 84:     gColormap   = DefaultColormap(display,screen);
 85:   }

 87:   /* set the basic colors into the color map */
 88:   for (i=0; i<PETSC_DRAW_BASIC_COLORS; i++) {
 89:     XAllocNamedColor(display,gColormap,colornames[i],&colordef,&ecolordef);
 90:     gCmapping[i] = colordef.pixel;
 91:   }

 93:   /* set the uniform hue colors into the color map */
 94:   ncolors = 256-PETSC_DRAW_BASIC_COLORS;
 95:   ierr    = PetscMalloc(3*ncolors*sizeof(unsigned char),&red);
 96:   green   = red   + ncolors;
 97:   blue    = green + ncolors;
 98:   ierr    = PetscDrawUtilitySetCmapHue(red,green,blue,ncolors);
 99:   ierr    = PetscOptionsHasName(PETSC_NULL,"-draw_fast",&fast);
100:   if (!fast) {
101:     for (i=PETSC_DRAW_BASIC_COLORS; i<ncolors+PETSC_DRAW_BASIC_COLORS; i++) {
102:       colordef.red    = ((int)red[i-PETSC_DRAW_BASIC_COLORS]   * 65535) / 255;
103:       colordef.green  = ((int)green[i-PETSC_DRAW_BASIC_COLORS] * 65535) / 255;
104:       colordef.blue   = ((int)blue[i-PETSC_DRAW_BASIC_COLORS]  * 65535) / 255;
105:       colordef.flags  = DoRed | DoGreen | DoBlue;
106:       XAllocColor(display,gColormap,&colordef);
107:       gCmapping[i]   = colordef.pixel;
108:     }
109:   }
110:   PetscFree(red);
111:   PetscLogInfo(0,"PetscDrawSetUpColormap_Shared:Successfully allocated colorsn");

113:   return(0);
114: }

116: /*
117:     Keep a record of which pixel numbers in the cmap have been 
118:   used so far; this is to allow us to try to reuse as much of the current
119:   colormap as possible.
120: */
121: static PetscTruth cmap_pixvalues_used[256];
122: static int        cmap_base = 0;

124: int PetscDrawSetUpColormap_Private(Display *display,int screen,Visual *visual,Colormap colormap)
125: {
126:   Colormap      defaultmap = DefaultColormap(display,screen);
127:   int           ierr,found,i,ncolors;
128:   XColor        colordef;
129:   unsigned char *red,*green,*blue;
130:   PetscTruth    fast;


134:   if (colormap) {
135:     gColormap = colormap;
136:   } else {
137:     gColormap = XCreateColormap(display,RootWindow(display,screen),visual,AllocAll);
138:   }

140:   cmap_base = 0;
141:   PetscMemzero(cmap_pixvalues_used,256*sizeof(PetscTruth));

143:   /* set the basic colors into the color map */
144:   for (i=0; i<PETSC_DRAW_BASIC_COLORS; i++) {
145:     XParseColor(display,gColormap,colornames[i],&colordef);
146:       /* try to allocate the color in the default-map */
147:     found = XAllocColor(display,defaultmap,&colordef);
148:     /* use it, if it it exists and is not already used in the new colormap */
149:     if (found && colordef.pixel < 256  && !cmap_pixvalues_used[colordef.pixel]) {
150:       cmap_pixvalues_used[colordef.pixel] = PETSC_TRUE;
151:     /* otherwise search for the next available slot */
152:     } else {
153:       while (cmap_pixvalues_used[cmap_base]) cmap_base++;
154:       colordef.pixel                   = cmap_base;
155:       cmap_pixvalues_used[cmap_base++] = PETSC_TRUE;
156:     }
157:     XStoreColor(display,gColormap,&colordef);
158:     gCmapping[i] = colordef.pixel;
159:   }

161:   /* set the uniform hue colors into the color map */
162:   ncolors = 256-PETSC_DRAW_BASIC_COLORS;
163:   ierr    = PetscMalloc(3*ncolors*sizeof(unsigned char),&red);
164:   green   = red   + ncolors;
165:   blue    = green + ncolors;
166:   ierr    = PetscDrawUtilitySetCmapHue(red,green,blue,ncolors);
167:   ierr    = PetscOptionsHasName(PETSC_NULL,"-draw_fast",&fast);
168:   if (!fast) {
169:     for (i=PETSC_DRAW_BASIC_COLORS; i<ncolors+PETSC_DRAW_BASIC_COLORS; i++) {
170:       colordef.red    = ((int)red[i-PETSC_DRAW_BASIC_COLORS]   * 65535) / 255;
171:       colordef.green  = ((int)green[i-PETSC_DRAW_BASIC_COLORS] * 65535) / 255;
172:       colordef.blue   = ((int)blue[i-PETSC_DRAW_BASIC_COLORS]  * 65535) / 255;
173:       colordef.flags  = DoRed | DoGreen | DoBlue;
174:       /* try to allocate the color in the default-map */
175:       found = XAllocColor(display,defaultmap,&colordef);
176:       /* use it, if it it exists and is not already used in the new colormap */
177:       if (found && colordef.pixel < 256  && !cmap_pixvalues_used[colordef.pixel]) {
178:         cmap_pixvalues_used[colordef.pixel] = PETSC_TRUE;
179:         /* otherwise search for the next available slot */
180:       } else {
181:         while (cmap_pixvalues_used[cmap_base]) cmap_base++;
182:         colordef.pixel                   = cmap_base;
183:         cmap_pixvalues_used[cmap_base++] = PETSC_TRUE;
184:       }
185:       XStoreColor(display,gColormap,&colordef);
186:       gCmapping[i]   = colordef.pixel;
187:     }
188:   }
189:   PetscFree(red);
190:   PetscLogInfo(0,"PetscDrawSetUpColormap_Private:Successfully allocated colorsn");
191:   return(0);
192: }

194: int PetscDrawSetUpColormap_X(Display *display,int screen,Visual *visual,Colormap colormap)
195: {
196:   int         ierr;
197:   PetscTruth  sharedcolormap;
198:   XVisualInfo vinfo;


202:   /* 
203:      This is wrong; it needs to take the value from the visual 
204:   */
205:   gNumcolors = 1 << DefaultDepth(display,screen);

207:   PetscOptionsHasName(PETSC_NULL,"-draw_x_shared_colormap",&sharedcolormap);
208:   /*
209:         Need to determine if window supports allocating a private colormap,
210:     if not, set flag to 1
211:   */
212:   if (XMatchVisualInfo(display,screen,24,StaticColor,&vinfo) ||
213:       XMatchVisualInfo(display,screen,24,TrueColor,&vinfo)   ||
214:       XMatchVisualInfo(display,screen,16,StaticColor,&vinfo) ||
215:       XMatchVisualInfo(display,screen,16,TrueColor,&vinfo)   ||
216:       XMatchVisualInfo(display,screen,15,StaticColor,&vinfo) ||
217:       XMatchVisualInfo(display,screen,15,TrueColor,&vinfo)) {
218:     sharedcolormap = PETSC_TRUE;
219:   }

221:   /* generate the X color map object */
222:   if (sharedcolormap) {
223:     PetscDrawSetUpColormap_Shared(display,screen,visual,colormap);
224:   } else {
225:     PetscDrawSetUpColormap_Private(display,screen,visual,colormap);
226:   }
227: 
228:   return(0);
229: }

231: int PetscDrawSetColormap_X(PetscDraw_X* XiWin,char *host,Colormap colormap)
232: {

236:   if (XiWin->depth < 8) {
237:     SETERRQ(1,"PETSc Graphics require monitors with at least 8 bit color (256 colors)");
238:   }
239:   if (!gColormap){
240:     Display  *display;  /* Private display will exist forever contains colormap shared by all windows */
241:     int      screen;
242:     Visual*  vis;

244:     display = XOpenDisplay(host);
245:     screen  = DefaultScreen(display);
246:     vis     = DefaultVisual(display,screen);

248:     PetscDrawSetUpColormap_X(display,screen,vis,colormap);
249:   }
250:   XiWin->cmap = gColormap;
251:   PetscMemcpy(XiWin->cmapping,gCmapping,256*sizeof(PixVal));
252:   XiWin->background = XiWin->cmapping[PETSC_DRAW_WHITE];
253:   XiWin->foreground = XiWin->cmapping[PETSC_DRAW_BLACK];
254:   return(0);
255: }

257: /*
258:     Color in X is many-layered.  The first layer is the "visual",a
259:     immutable attribute of a window set when the window is
260:     created.

262:     The next layer is the colormap.  The installation of colormaps is
263:     the buisness of the window manager (in some distant later release).
264: */

266: /*
267:     This routine gets the visual class (PseudoColor, etc) and returns
268:     it.  It finds the default visual.  Possible returns are
269:         PseudoColor
270:         StaticColor
271:         DirectColor
272:         TrueColor
273:         GrayScale
274:         StaticGray
275:  */
276: int XiSetVisualClass(PetscDraw_X* XiWin)
277: {
278:   XVisualInfo vinfo;

281:   if (XMatchVisualInfo(XiWin->disp,XiWin->screen,24,DirectColor,&vinfo)) {
282:     XiWin->vis    = vinfo.visual;
283:     return(0);
284:   }
285:   if (XMatchVisualInfo(XiWin->disp,XiWin->screen,8,PseudoColor,&vinfo)) {
286:     XiWin->vis    = vinfo.visual;
287:     return(0);
288:   }
289:   if (XMatchVisualInfo(XiWin->disp,XiWin->screen,
290:     DefaultDepth(XiWin->disp,XiWin->screen),PseudoColor,&vinfo)) {
291:     XiWin->vis    = vinfo.visual;
292:     return(0);
293:   }
294:   XiWin->vis    = DefaultVisual(XiWin->disp,XiWin->screen);
295:   return(0);
296: }

298: int XiGetVisualClass(PetscDraw_X* XiWin)
299: {
301: #if defined(__cplusplus)
302:   PetscFunctionReturn(XiWin->vis->c_class);
303: #else
304:   PetscFunctionReturn(XiWin->vis->class);
305: #endif
306: }


309: int XiSetColormap(PetscDraw_X* XiWin)
310: {
312:   XSetWindowColormap(XiWin->disp,XiWin->win,XiWin->cmap);
313:   return(0);
314: }

316: int XiGetBaseColor(PetscDraw_X* XiWin,PixVal* white_pix,PixVal* black_pix)
317: {
319:   *white_pix  = XiWin->cmapping[PETSC_DRAW_WHITE];
320:   *black_pix  = XiWin->cmapping[PETSC_DRAW_BLACK];
321:   return(0);
322: }



326: /*
327:     This routine returns the pixel value for the specified color
328:     Returns 0 on failure,<>0 otherwise.
329:  */
330: int XiFindColor(PetscDraw_X *XiWin,char *name,PixVal *pixval)
331: {
332:   XColor   colordef;
333:   int      st;

336:   st = XParseColor(XiWin->disp,XiWin->cmap,name,&colordef);
337:   if (st) {
338:     st  = XAllocColor(XiWin->disp,XiWin->cmap,&colordef);
339:     if (st)  *pixval = colordef.pixel;
340:   }
341:   PetscFunctionReturn(st);
342: }

344: /*
345:     Another real need is to assign "colors" that make sense for
346:     a monochrome display,without unduely penalizing color displays.
347:     This routine takes a color name,a window, and a flag that
348:     indicates whether this is "background" or "foreground".
349:     In the monchrome case (or if the color is otherwise unavailable),
350:     the "background" or "foreground" colors will be chosen
351:  */
352: PixVal XiGetColor(PetscDraw_X* XiWin,char *name,int is_fore)
353: {
354:   PixVal pixval;

357:   if (XiWin->numcolors == 2 || !XiFindColor(XiWin,name,&pixval)) {
358:     pixval  = is_fore ? XiWin->cmapping[PETSC_DRAW_WHITE] : XiWin->cmapping[PETSC_DRAW_BLACK];
359:   }
360:   PetscFunctionReturn(pixval);
361: }

363: /*
364:    This routine takes a named color and returns a color that is either
365:    lighter or darker
366:  */
367: PixVal XiSimColor(PetscDraw_X *XiWin,PixVal pixel,int intensity,int is_fore)
368: {
369:   XColor   colordef,colorsdef;
370:   char     RGBcolor[20];
371:   PixVal   red,green,blue;

374:   colordef.pixel = pixel;
375:   XQueryColor(XiWin->disp,XiWin->cmap,&colordef);
376:   /* Adjust the color value up or down.  Get the RGB values for the color */
377:   red   = colordef.red;
378:   green = colordef.green;
379:   blue  = colordef.blue;
380: #define WHITE_AMOUNT 5000
381:   if (intensity > 0) {
382:     /* Add white to the color */
383:     red   = PetscMin(65535,red + WHITE_AMOUNT);
384:     green = PetscMin(65535,green + WHITE_AMOUNT);
385:     blue  = PetscMin(65535,blue + WHITE_AMOUNT);
386:   } else {
387:     /* Subtract white from the color */
388:     red   = (red   < WHITE_AMOUNT) ? 0 : red - WHITE_AMOUNT;
389:     green = (green < WHITE_AMOUNT) ? 0 : green - WHITE_AMOUNT;
390:     blue  = (blue  < WHITE_AMOUNT) ? 0 : blue - WHITE_AMOUNT;
391:   }
392:   sprintf(RGBcolor,"rgb:%4.4x/%4.4x/%4.4x",(unsigned int)red,
393:                      (unsigned int)green,(unsigned int)blue);
394:   XLookupColor(XiWin->disp,XiWin->cmap,RGBcolor,&colordef,&colorsdef);
395:   PetscFunctionReturn(colorsdef.pixel);
396: }

398: /*
399:   XiSetCmapLight - Create rgb values from a single color by adding white
400:   
401:   The initial color is (red[0],green[0],blue[0]).
402: */
403: int XiSetCmapLight(unsigned char *red,unsigned char *green,unsigned char *blue,int mapsize)
404: {
405:   int     i ;

408:   for (i=1; i<mapsize-1; i++) {
409:       blue[i]  = i*(255-(int)blue[0])/(mapsize-2)+blue[0] ;
410:       green[i] = i*(255-(int)green[0])/(mapsize-2)+green[0] ;
411:       red[i]   = i*(255-(int)red[0])/(mapsize-2)+red[0] ;
412:   }
413:   red[mapsize-1] = green[mapsize-1] = blue[mapsize-1] = 255;
414:   return(0);
415: }