]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gdk_imlib/cache.c
Initial revision
[wxWidgets.git] / src / gdk_imlib / cache.c
diff --git a/src/gdk_imlib/cache.c b/src/gdk_imlib/cache.c
new file mode 100644 (file)
index 0000000..4e750df
--- /dev/null
@@ -0,0 +1,496 @@
+#define _GNU_SOURCE
+#include "gdk_imlib.h"
+#include "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);
+}