/**************************************************************************** * This module is all original code * by Rob Nation * Copyright 1993, Robert Nation * You may use this code for any purpose, as long as the original * copyright remains in the source code and all documentation ****************************************************************************/ /* Changed 02/12/97 by Dan Espen: - added routines to determine color closeness, for color use reduction. Some of the logic comes from pixy2, so the copyright is below. */ /* * $Id: Picture.c,v 1.1 2006/11/26 10:53:41 matthieu Exp $ * Copyright 1996, Romano Giannetti. No guarantees or warantees or anything * are provided or implied in any way whatsoever. Use this program at your * own risk. Permission to use this program for any purpose is given, * as long as the copyright is kept intact. * * Romano Giannetti - Dipartimento di Ingegneria dell'Informazione * via Diotisalvi, 2 PISA * mailto:romano@iet.unipi.it * http://www.iet.unipi.it/~romano * */ /**************************************************************************** * * Routines to handle initialization, loading, and removing of xpm's or mono- * icon images. * ****************************************************************************/ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef XPM /* static function prototypes */ static void c100_init_base_table (); /* prototype */ static void c200_substitute_color(char **,int); /* prototype */ static void c300_color_to_rgb(char *, XColor *); /* prototype */ static double c400_distance(XColor *, XColor *); /* prototype */ #endif #include "fvwmlib.h" static Picture *PictureList=NULL; Colormap PictureCMap; Display *PictureSaveDisplay; /* Save area for display pointer */ /* This routine called during fvwm and some modules initialization */ void InitPictureCMap(Display *dpy,Window Root) { XWindowAttributes root_attr; PictureSaveDisplay = dpy; /* save for latter */ XGetWindowAttributes(dpy,Root,&root_attr); PictureCMap=root_attr.colormap; } Picture *LoadPicture(Display *dpy,Window Root,char *path, int color_limit) { int l; Picture *p; #ifdef XPM XpmAttributes xpm_attributes; int rc; XpmImage my_image = {0}; #endif p=(Picture*)safemalloc(sizeof(Picture)); p->count=1; p->name=path; p->next=NULL; #ifdef XPM /* Try to load it as an X Pixmap first */ xpm_attributes.colormap=PictureCMap; xpm_attributes.closeness=40000; /* Allow for "similar" colors */ xpm_attributes.valuemask= XpmSize | XpmReturnPixels | XpmColormap | XpmCloseness; rc =XpmReadFileToXpmImage(path, &my_image, NULL); if (rc == XpmSuccess) { color_reduce_pixmap(&my_image, color_limit); rc = XpmCreatePixmapFromXpmImage(dpy, Root, &my_image, &p->picture,&p->mask, &xpm_attributes); if (rc == XpmSuccess) { p->width = my_image.width; p->height = my_image.height; XpmFreeXpmImage(&my_image); p->depth = DefaultDepthOfScreen(DefaultScreenOfDisplay(dpy)); return p; } XpmFreeXpmImage(&my_image); } #endif /* If no XPM support, or XPM loading failed, try bitmap */ if(XReadBitmapFile(dpy,Root,path,&p->width,&p->height,&p->picture,&l,&l) == BitmapSuccess) { p->depth = 0; p->mask = None; return p; } free(p); return NULL; } Picture *GetPicture(Display *dpy,Window Root,char *IconPath,char *PixmapPath, char *name, int color_limit) { char *path; Picture *p; if(!(path=findIconFile(name,PixmapPath,R_OK))) if(!(path=findIconFile(name,IconPath,R_OK))) return NULL; p = LoadPicture(dpy,Root,path, color_limit); if (!p) free(path); return p; } Picture *CachePicture(Display *dpy,Window Root,char *IconPath,char *PixmapPath, char *name, int color_limit) { char *path; Picture *p=PictureList; /* First find the full pathname */ #ifdef XPM if(!(path=findIconFile(name,PixmapPath,R_OK))) if(!(path=findIconFile(name,IconPath,R_OK))) return NULL; #else /* Ignore the given pixmap path when compiled without XPM support */ if(!(path=findIconFile(name,IconPath,R_OK))) return NULL; #endif /* See if the picture is already cached */ while(p) { register char *p1, *p2; for (p1=path, p2=p->name; *p1 && *p2; ++p1, ++p2) if (*p1 != *p2) break; if(!*p1 && !*p2) /* We have found a picture with the wanted name */ { p->count++; /* Put another weight on the picture */ free(path); return p; } p=p->next; } /* Not previously cached, have to load it ourself. Put it first in list */ p=LoadPicture(dpy,Root,path, color_limit); if(p) { p->next=PictureList; PictureList=p; } else free(path); return p; } void DestroyPicture(Display *dpy,Picture *p) { Picture *q=PictureList; if (!p) /* bag out if NULL */ return; if(--(p->count)>0) /* Remove a weight, still too heavy? */ return; /* Let it fly */ if(p->name!=NULL) free(p->name); if(p->picture!=None) XFreePixmap(dpy,p->picture); if(p->mask!=None) XFreePixmap(dpy,p->mask); /* Link it out of the list (it might not be there) */ if(p==q) /* in head? simple */ PictureList=p->next; else { while(q && q->next!=p) /* fast forward until end or found */ q=q->next; if(q) /* not end? means we found it in there, possibly at end */ q->next=p->next; /* link around it */ } free(p); } /**************************************************************************** * * Find the specified icon file somewhere along the given path. * * There is a possible race condition here: We check the file and later * do something with it. By then, the file might not be accessible. * Oh well. * ****************************************************************************/ char *findIconFile(char *icon, char *pathlist, int type) { char *path; char *dir_end; int l; size_t pathlen; if (!icon) return NULL; l = (pathlist) ? strlen(pathlist) : 0; pathlen = strlen(icon) + l + 10; path = safemalloc(pathlen); *path = '\0'; if (*icon == '/' || pathlist == NULL || *pathlist == '\0') { /* No search if icon begins with a slash */ /* No search if pathlist is empty */ strlcpy(path, icon, pathlen); return path; } /* Search each element of the pathlist for the icon file */ while ((pathlist)&&(*pathlist)) { dir_end = strchr(pathlist, ':'); if (dir_end != NULL) { strncpy(path, pathlist, dir_end - pathlist); path[dir_end - pathlist] = 0; } else strlcpy(path, pathlist, pathlen); strlcat(path, "/", pathlen); strlcat(path, icon, pathlen); if (access(path, type) == 0) return path; strlcat(path, ".gz", pathlen); if (access(path, type) == 0) return path; /* Point to next element of the path */ if(dir_end == NULL) pathlist = NULL; else pathlist = dir_end + 1; } /* Hmm, couldn't find the file. Return NULL */ free(path); return NULL; } #ifdef XPM /* This structure is used to quickly access the RGB values of the colors */ /* without repeatedly having to transform them. */ typedef struct { char * c_color; /* Pointer to the name of the color */ XColor rgb_space; /* rgb color info */ } Color_Info; /* First thing in base array are colors probably already in the color map because they have familiar names. I pasted them into a xpm and spread them out so that similar colors are spread out. Toward the end are some colors to fill in the gaps. Currently 61 colors in this list. */ static Color_Info base_array[] = { {"white"}, {"black"}, {"grey"}, {"green"}, {"blue"}, {"red"}, {"cyan"}, {"yellow"}, {"magenta"}, {"DodgerBlue"}, {"SteelBlue"}, {"chartreuse"}, {"wheat"}, {"turquoise"}, {"CadetBlue"}, {"gray87"}, {"CornflowerBlue"}, {"YellowGreen"}, {"NavyBlue"}, {"MediumBlue"}, {"plum"}, {"aquamarine"}, {"orchid"}, {"ForestGreen"}, {"lightyellow"}, {"brown"}, {"orange"}, {"red3"}, {"HotPink"}, {"LightBlue"}, {"gray47"}, {"pink"}, {"red4"}, {"violet"}, {"purple"}, {"gray63"}, {"gray94"}, {"plum1"}, {"PeachPuff"}, {"maroon"}, {"lavender"}, {"salmon"}, /* for peachpuff, orange gap */ {"blue4"}, /* for navyblue/mediumblue gap */ {"PaleGreen4"}, /* for forestgreen, yellowgreen gap */ {"#AA7700"}, /* brick, no close named color */ {"#11EE88"}, /* light green, no close named color */ {"#884466"}, /* dark brown, no close named color */ {"#CC8888"}, /* light brick, no close named color */ {"#EECC44"}, /* gold, no close named color */ {"#AAAA44"}, /* dull green, no close named color */ {"#FF1188"}, /* pinkish red */ {"#992299"}, /* purple */ {"#CCFFAA"}, /* light green */ {"#664400"}, /* dark brown*/ {"#AADD99"}, /* light green */ {"#66CCFF"}, /* light blue */ {"#CC2299"}, /* dark red */ {"#FF11CC"}, /* bright pink */ {"#11CC99"}, /* grey/green */ {"#AA77AA"}, /* purple/red */ {"#EEBB77"} /* orange/yellow */ }; #define NColors (sizeof(base_array) / sizeof(Color_Info)) /* if c_color isn't set, copy it from one of the other colours */ Bool xpmcolor_require_c_color(XpmColor *p) { if (p->c_color != NULL) return False; else if (p->g_color != NULL) p->c_color = strdup(p->g_color); else if (p->g4_color != NULL) p->c_color = strdup(p->g4_color); else if (p->m_color != NULL) p->c_color = strdup(p->m_color); else p->c_color = strdup("none"); return True; } /* given an xpm, change colors to colors close to the subset above. */ void color_reduce_pixmap(XpmImage *image,int color_limit) { int i; XpmColor *color_table_ptr; static char base_init = 'n'; if (color_limit > 0) { /* If colors to be limited */ if (base_init == 'n') { /* if base table not created yet */ c100_init_base_table(); /* init the base table */ base_init = 'y'; /* remember that its set now. */ } /* end base table init */ color_table_ptr = image->colorTable; /* start of xpm color table */ for(i=0; incolors; i++) { /* all colors in the xpm */ /* Theres an array for this in the xpm library, but it doesn't appear to be part of the API. Too bad. dje 01/09/00 */ char **visual_color = 0; if (color_table_ptr->c_color) { visual_color = &color_table_ptr->c_color; } else if (color_table_ptr->g_color) { visual_color = &color_table_ptr->g_color; } else if (color_table_ptr->g4_color) { visual_color = &color_table_ptr->g4_color; } else { /* its got to be one of these */ visual_color = &color_table_ptr->m_color; } c200_substitute_color(visual_color,color_limit); color_table_ptr +=1; /* counter for loop */ } /* end all colors in xpm */ } /* end colors limited */ return; /* return, no rc! */ } /* from the color names in the base table, calc rgbs */ static void c100_init_base_table () { int i; for (i=0; ired - target_ptr->red )/655.35) + SQUARE((double)(base_ptr->green - target_ptr->green)/655.35) + SQUARE((double)(base_ptr->blue - target_ptr->blue )/655.35); return dst; } #endif /* XPM */