#define _GNU_SOURCE #include "../gdk_imlib/gdk_imlib.h" #include "../gdk_imlib/gdk_imlib_private.h" /* uncomment this to compile imlib's cahce with pixmap accounting output */ /*#define PIXMAP_ACCOUNTING */ void gdirty_pixmaps(GdkImlibImage * im) { struct pixmap_cache *ptr; ptr = id->cache.pixmap; while (ptr) { if ((ptr->im == im) && ((!ptr->file) || (!strcmp(im->filename, ptr->file)))) ptr->dirty = 1; ptr = ptr->next; } } void gdirty_images(GdkImlibImage * 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; } } void gfind_pixmap(GdkImlibImage * im, int width, int height, GdkPixmap ** pmap, GdkBitmap ** mask) { struct pixmap_cache *ptr; ptr = id->cache.pixmap; while (ptr) { if ((ptr->im == im) && (ptr->width == width) && (ptr->height == height) && ((!ptr->file) || (!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 = NULL; *mask = NULL; } GdkImlibImage * gfind_image(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 gfree_pixmappmap(GdkPixmap * 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; } gdk_pixmap_unref(pmap); } void gfree_image(GdkImlibImage * im) { struct image_cache *ptr; ptr = id->cache.image; while (ptr) { if (im == ptr->im) { if (ptr->refnum) { ptr->refnum--; if (!ptr->refnum) { id->cache.num_image--; id->cache.used_image += ptr->im->rgb_width * ptr->im->rgb_height * 3; } } return; } ptr = ptr->next; } gnullify_image(im); } void gflush_image(GdkImlibImage * im) { if (im) im->cache = 0; } void gadd_image(GdkImlibImage * 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 gadd_pixmap(GdkImlibImage * 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 gclean_caches() { { struct image_cache *ptr = NULL; struct image_cache *pptr = NULL; struct image_cache *last = NULL; int newlast; /* 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) { if (!ptr->im->cache) { if (ptr == last) newlast = 1; id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; gnullify_image(ptr->im); if (pptr) ptr = pptr->prev; 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); free(ptr); ptr = NULL; } } if (ptr) ptr = ptr->prev; if (newlast) { last = NULL; ptr = id->cache.image; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; } } /* find the back of the list */ ptr = id->cache.image; last = NULL; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; /* 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) { while (ptr) { if (ptr->refnum < 1) { if (ptr == last) newlast = 1; id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; gnullify_image(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); free(ptr); ptr = NULL; break; } if (ptr) ptr = ptr->prev; } if (newlast) { last = NULL; ptr = id->cache.image; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; } if (!ptr) break; } } { struct pixmap_cache *ptr; struct pixmap_cache *last; int newlast; #ifdef PIXMAP_ACCOUNTING int total, total2, num, num2; printf("--------- Pixmap cashe zise %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) { printf("Pmap for file %s 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; } printf("Accounting Data:\n"); printf("*** total pixmap's in cache %i with %i pixmaps\n", total, num); printf("*** total unreffed pixmap's in cache %i with %i pixmaps\n\n", total2, num2); #endif /* find the back of the list */ ptr = id->cache.pixmap; last = NULL; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; /* while 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 (id->cache.used_pixmap > id->cache.size_pixmap) { while (ptr) { if (ptr->refnum < 1) { if (ptr == last) newlast = 1; 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) gdk_pixmap_unref(ptr->pmap); if (ptr->shape_mask) gdk_pixmap_unref(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); free(ptr); ptr = NULL; break; } if (ptr) ptr = ptr->prev; } if (newlast) { last = NULL; ptr = id->cache.pixmap; while (ptr) { last = ptr; ptr = ptr->next; } newlast = 0; ptr = last; } if (!ptr) break; } } } void gnullify_image(GdkImlibImage * im) { if (!im) return; if (im->rgb_data) free(im->rgb_data); if (im->alpha_data) free(im->alpha_data); if (im->pixmap) gfree_pixmappmap(im->pixmap); if (im->filename) free(im->filename); free(im); }