#define _GNU_SOURCE #include #include "Imlib.h" #include "Imlib_private.h" /* uncomment this to compile imlib's cahce with pixmap accounting output */ /*#define PIXMAP_ACCOUNTING*/ /* uncomment this to compile imlib's cahce with image accounting output */ /*#define IMAGE_ACCOUNTING*/ void dirty_pixmaps(ImlibData * id, ImlibImage * im) { struct pixmap_cache *ptr; ptr = id->cache.pixmap; while (ptr) { if ((ptr->im == im) && ((!ptr->file) || ((ptr->file) && (im->filename) && (!strcmp(im->filename, ptr->file))))) ptr->dirty = 1; ptr = ptr->next; } clean_caches(id); } void dirty_images(ImlibData * id, ImlibImage * im) { struct image_cache *ptr; ptr = id->cache.image; while (ptr) { if ((!strcmp(im->filename, ptr->file)) && (im == ptr->im)) { ptr->dirty = 1; return; } ptr = ptr->next; } clean_caches(id); } void find_pixmap(ImlibData * id, ImlibImage * im, int width, int height, Pixmap * pmap, Pixmap * mask) { struct pixmap_cache *ptr; ptr = id->cache.pixmap; while (ptr) { if ((ptr->im == im) && (ptr->width == width) && (ptr->height == height) && ((!ptr->file) || ((ptr->file) && (im->filename) && (!strcmp(im->filename, ptr->file)))) && (!ptr->dirty)) { if (ptr->refnum > 0) ptr->refnum++; else { ptr->refnum++; id->cache.num_pixmap++; if (ptr->pmap) id->cache.used_pixmap -= width * height * id->x.depth; if (ptr->shape_mask) id->cache.used_pixmap -= width * height; if (id->cache.used_pixmap < 0) { id->cache.used_pixmap = 0; fprintf(stderr, "IMLIB: uhoh.. caching problems.... meep meep\n"); } } if (ptr->prev) { ptr->prev->next = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; ptr->next = id->cache.pixmap; ptr->next->prev = ptr; id->cache.pixmap = ptr; ptr->prev = NULL; } *pmap = ptr->pmap; *mask = ptr->shape_mask; return; } ptr = ptr->next; } *pmap = 0; *mask = 0; } ImlibImage * find_image(ImlibData * id, char *file) { struct image_cache *ptr; ptr = id->cache.image; while (ptr) { if ((!strcmp(file, ptr->file)) && (!ptr->dirty)) { if (ptr->refnum) ptr->refnum++; else { ptr->refnum++; id->cache.num_image++; id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; if (id->cache.used_image < 0) { id->cache.used_image = 0; fprintf(stderr, "IMLIB: uhoh.. caching problems.... meep meep\n"); } } if (ptr->prev) { ptr->prev->next = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; ptr->next = id->cache.image; ptr->next->prev = ptr; id->cache.image = ptr; ptr->prev = NULL; } return ptr->im; } ptr = ptr->next; } return NULL; } void free_pixmappmap(ImlibData * id, Pixmap pmap) { struct pixmap_cache *ptr; ptr = id->cache.pixmap; while (ptr) { if ((ptr->pmap == pmap) || (ptr->shape_mask == pmap)) { if (ptr->shape_mask == pmap) return; if (ptr->refnum > 0) { ptr->refnum--; if (ptr->refnum == 0) { id->cache.num_pixmap--; if (ptr->pmap) id->cache.used_pixmap += ptr->width * ptr->height * id->x.depth; if (ptr->shape_mask) id->cache.used_pixmap += ptr->width * ptr->height; } } return; } ptr = ptr->next; } XFreePixmap(id->x.disp, pmap); } void free_image(ImlibData * id, ImlibImage * im) { struct image_cache *ptr; ptr = id->cache.image; while (ptr) { if (im == ptr->im) { if (ptr->refnum) { ptr->refnum--; if (ptr->refnum == 0) { id->cache.num_image--; id->cache.used_image += ptr->im->rgb_width * ptr->im->rgb_height * 3; if (im->pixmap) { free_pixmappmap(id, im->pixmap); im->pixmap = 0; im->shape_mask = 0; } } } return; } ptr = ptr->next; } nullify_image(id, im); } void flush_image(ImlibData * id, ImlibImage * im) { if (im) im->cache = 0; } void add_image(ImlibData * id, ImlibImage * im, char *file) { struct image_cache *ptr; struct image_cache *n; if ((!im) || (!file)) return; ptr = id->cache.image; n = malloc(sizeof(struct image_cache)); if (!n) return; n->prev = NULL; n->next = ptr; n->file = malloc(strlen(file) + 1); if (!n->file) { free(n); return; } strcpy(n->file, file); n->im = im; n->refnum = 1; n->dirty = 0; if (n->next) n->next->prev = n; id->cache.image = n; id->cache.num_image++; } void add_pixmap(ImlibData * id, ImlibImage * im, int width, int height, XImage * xim, XImage * sxim) { struct pixmap_cache *ptr; struct pixmap_cache *n; if (!im) return; ptr = id->cache.pixmap; n = malloc(sizeof(struct pixmap_cache)); if (!n) return; n->prev = NULL; n->next = ptr; n->im = im; if (im->filename) { n->file = malloc(strlen(im->filename) + 1); if (n->file) strcpy(n->file, im->filename); } else n->file = NULL; n->refnum = 1; n->dirty = 0; n->width = width; n->height = height; n->pmap = im->pixmap; n->shape_mask = im->shape_mask; n->xim = xim; n->sxim = sxim; if (n->next) n->next->prev = n; id->cache.pixmap = n; id->cache.num_pixmap++; } void clean_caches(ImlibData * id) { { struct image_cache *ptr = NULL; struct image_cache *pptr = NULL; struct image_cache *last = NULL; int newlast; #ifdef IMAGE_ACCOUNTING int total, total2, num, num2; fprintf(stderr, "--------- Image cache sise %i / %i with %i images referenced\n", id->cache.used_image, id->cache.size_image, id->cache.num_image); ptr = id->cache.image; total = 0; total2 = 0; num = 0; num2 = 0; while (ptr) { fprintf(stderr, "Image for file %80s REFNUM %3i SIZE %4ix%4i\n", ptr->file, ptr->refnum, ptr->im->rgb_width, ptr->im->rgb_height); if (ptr->refnum > 0) { total += (ptr->im->rgb_width * ptr->im->rgb_height * 3); num++; } else { total2 += (ptr->im->rgb_width * ptr->im->height * 3); num2++; } ptr = ptr->next; } fprintf(stderr, "Accounting Data:\n"); fprintf(stderr, "*** total images in cache %i with %i images\n", total, num); fprintf(stderr, "*** total unref images in cache %i with %i images\n\n", total2, num2); #endif /* find the back of the list */ ptr = id->cache.image; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; /* remove all images that are tagged non-cachable, and have 0 */ /* references , even if the cache has spare room. */ while (ptr) { if (ptr->refnum <= 0) { if (!ptr->im->cache) { id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; nullify_image(id, ptr->im); if (ptr->prev) ptr->prev->next = ptr->next; else id->cache.image = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; if (ptr->file) free(ptr->file); last = ptr; ptr = ptr->prev; free(last); } else ptr = ptr->prev; } else ptr = ptr->prev; } /* find the back of the list */ ptr = id->cache.image; last = NULL; while (ptr) { last = ptr; ptr = ptr->next; } ptr = last; newlast = 0; /* while the amount of data in the cache is greater than the set */ /* amount, delete the last entry (last used) from the unreferenced */ /* cached 24-bit images */ while (id->cache.used_image > id->cache.size_image) { if (newlast) { ptr = id->cache.image; last = NULL; while (ptr) { last = ptr; ptr = ptr->next; } ptr = last; newlast = 0; } while (ptr) { if (ptr->refnum <= 0) { id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; nullify_image(id, ptr->im); if (ptr->prev) ptr->prev->next = ptr->next; else id->cache.image = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; if (ptr->file) free(ptr->file); last = ptr; ptr = ptr->prev; free(last); newlast = 1; } else ptr = ptr->prev; if (id->cache.used_image <= id->cache.size_image) ptr = NULL; } } } { struct pixmap_cache *ptr; struct pixmap_cache *last; int newlast; #ifdef PIXMAP_ACCOUNTING int total, total2, num, num2; fprintf(stderr, "--------- Pixmap cache sie %i / %i with %i pixmaps referenced\n", id->cache.used_pixmap, id->cache.size_pixmap, id->cache.num_pixmap); ptr = id->cache.pixmap; total = 0; total2 = 0; num = 0; num2 = 0; while (ptr) { fprintf(stderr, "Pmap for file %80s REFNUM %3i SIZE %4ix%4i" " PMAP %8x MASK %8x\n", ptr->file, ptr->refnum, ptr->width, ptr->height, ptr->pmap, ptr->shape_mask); if (ptr->refnum > 0) { total += (ptr->width * ptr->height * id->x.depth); if (ptr->shape_mask) total += (ptr->width * ptr->height); num++; } else { total2 += (ptr->width * ptr->height * id->x.depth); if (ptr->shape_mask) total2 += (ptr->width * ptr->height); num2++; } ptr = ptr->next; } fprintf(stderr, "Accounting Data:\n"); fprintf(stderr, "*** total pixmaps in cache %i with %i pixmaps\n", total, num); fprintf(stderr, "*** total unref pixmaps in cache %i with %i pixmaps\n\n", total2, num2); #endif ptr = id->cache.pixmap; while (ptr) { last = ptr->next; if ((ptr->dirty) && (ptr->refnum <= 0)) { if (ptr->pmap) id->cache.used_pixmap -= ptr->width * ptr->height * id->x.depth; if (ptr->shape_mask) id->cache.used_pixmap -= ptr->width * ptr->height; if (ptr->pmap) XFreePixmap(id->x.disp, ptr->pmap); if (ptr->shape_mask) XFreePixmap(id->x.disp, ptr->shape_mask); if (ptr->xim) XDestroyImage(ptr->xim); if (ptr->sxim) XDestroyImage(ptr->sxim); if (ptr->prev) ptr->prev->next = ptr->next; else id->cache.pixmap = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; free(ptr->file); free(ptr); } ptr = last; } /* find the back of the list */ last = NULL; ptr = id->cache.pixmap; while (ptr) { last = ptr; ptr = ptr->next; } ptr = last; /* the amount of data in the cache is greater than the set */ /* amount, delete the last entry (last used) from the unreferenced */ /* cached pixmaps */ while ((ptr) && (id->cache.used_pixmap > id->cache.size_pixmap)) { if (ptr->refnum <= 0) { if (ptr->pmap) id->cache.used_pixmap -= ptr->width * ptr->height * id->x.depth; if (ptr->shape_mask) id->cache.used_pixmap -= ptr->width * ptr->height; if (ptr->pmap) XFreePixmap(id->x.disp, ptr->pmap); if (ptr->shape_mask) XFreePixmap(id->x.disp, ptr->shape_mask); if (ptr->xim) XDestroyImage(ptr->xim); if (ptr->sxim) XDestroyImage(ptr->sxim); if (ptr->prev) ptr->prev->next = ptr->next; else id->cache.pixmap = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; if (ptr->file) free(ptr->file); last = ptr; ptr = ptr->prev; free(last); } else ptr = ptr->prev; if (id->cache.used_pixmap <= id->cache.size_pixmap) ptr = NULL; } } } void nullify_image(ImlibData * id, ImlibImage * im) { if (!im) return; if (im->rgb_data) free(im->rgb_data); if (im->alpha_data) free(im->alpha_data); if (im->pixmap) free_pixmappmap(id, im->pixmap); if (im->filename) free(im->filename); free(im); }