You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
554 lines
12 KiB
554 lines
12 KiB
#define _GNU_SOURCE
|
|
#include <config.h>
|
|
#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);
|
|
}
|