Logo Search packages:      
Sourcecode: galeon version File versions

galeon-favicon-cache.c

/*
 *  Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
 *  Copytight (C) 2005 Crispin Flowerday
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "galeon-favicon-cache.h"

#include <libgnomevfs/gnome-vfs-uri.h>
#include <libxml/tree.h>
#include <libxml/xmlwriter.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

#include "galeon-embed-persist.h"
#include "galeon-config.h"
#include "pixbuf-cache.h"
#include "gul-general.h"
#include "galeon-debug.h"

#define GALEON_FAVICON_CACHE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_FAVICON_CACHE, GaleonFaviconCachePrivate))

#define GALEON_FAVICON_CACHE_ENTRY_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_FAVICON_CACHE_ENTRY, GaleonFaviconCacheEntryPrivate))
/**
 * This structure contains the information on an individual image, 
 * multiple cache entries can reference this same struct, and the
 * pixbuf is not duplicated
 */
00051 typedef struct
{
      GaleonFaviconCache *cache; /* The parent cache */

      char *pixbuf_filename;   /* Filename on disk (if the image will be stored) */

      GList *entries; /* List of cache entries that references us */

      GdkPixbuf *pixbuf; /* The actual pixbuf */

      gboolean dirty:1; /* Is the pixbuf different from the on-disk version */
      gboolean on_disk:1; /* Is the pixbuf on disk */

} PixbufInfo;

struct _GaleonFaviconCachePrivate
{
      GHashTable *url_to_entry;
      GHashTable *filename_to_pixbuf;

      guint timeout;
      gboolean dirty;

      char *filename;
      char *directory;
};

struct _GaleonFaviconCacheEntryPrivate
{
      char *url;

      PixbufInfo *info;

      gboolean persistent;
};

enum
{
      PROP_0,
      PROP_PIXBUF,
      PROP_PERSISTENT
};

G_DEFINE_TYPE (GaleonFaviconCache, galeon_favicon_cache, G_TYPE_OBJECT);

/* ------------------------------------------------------------ 
 * PixbufInfo
 * ------------------------------------------------------------ */
static PixbufInfo *
pixbuf_info_new (const char *filename, GaleonFaviconCache *cache)
{
      PixbufInfo *ret;
      
      ret = g_new0 (PixbufInfo,1);
      
      ret->pixbuf_filename = g_strdup (filename);
      ret->dirty = FALSE;
      ret->on_disk = TRUE;
      ret->cache = cache;

      return ret;
}

static void
pixbuf_info_free (PixbufInfo *info)
{
      GList *l;

      if (info->pixbuf)
      {
            g_object_unref (info->pixbuf);
      }

      g_free (info->pixbuf_filename);

      /* Should only happen on GaleonFaviconCache finalize */
      for (l = info->entries ; l ; l = l->next)
      {
            GaleonFaviconCacheEntry *entry = l->data;
            entry->priv->info = NULL;

            /* remove the ref on the object as well */
            g_object_unref (G_OBJECT (entry));
      }
      g_list_free (info->entries);
      g_free (info);
}

static void
pixbuf_info_set_pixbuf (PixbufInfo *info, GdkPixbuf *pixbuf)
{
      GList *l;

      if (pixbuf == info->pixbuf)
      {
            return;
      }

      if (info->pixbuf)
      {
            g_object_unref (info->pixbuf);
      }

      info->pixbuf = g_object_ref (pixbuf);

      info->dirty = TRUE;

      for (l = info->entries ; l ; l = l->next)
      {
            g_object_notify (G_OBJECT (l->data), "pixbuf");
      }
}

static void
pixbuf_info_add_entry (PixbufInfo *info, GaleonFaviconCacheEntry *entry)
{
      info->entries = g_list_prepend (info->entries, entry);
}

static void
pixbuf_info_remove_entry (PixbufInfo *info, GaleonFaviconCacheEntry *entry)
{
      info->entries = g_list_remove_all (info->entries, entry);

      if (info->entries == NULL)
      {
            g_hash_table_remove (info->cache->priv->filename_to_pixbuf,
                             info);
      }
}


/* ------------------------------------------------------------ 
 * GaleonFaviconCacheEntry 
 * ------------------------------------------------------------ */
G_DEFINE_TYPE (GaleonFaviconCacheEntry, galeon_favicon_cache_entry, G_TYPE_OBJECT);

/** galeon_favicon_cache_entry_get_pixbuf:
 *  @entry: A #GaleonFaviconCacheEntry
 * 
 *  Get the pixbuf for the cache entry, if you want to keep the pixbuf, 
 *  you must add a reference count to it yourself using g_object_ref()
 *
 *  Return value: A #GdkPixbuf or NULL
 */
GdkPixbuf *
galeon_favicon_cache_entry_get_pixbuf (GaleonFaviconCacheEntry *entry)
{
      GdkPixbuf *pixbuf;

      g_return_val_if_fail (GALEON_IS_FAVICON_CACHE_ENTRY (entry), NULL);

      if (!entry->priv->info)
      {
            return NULL;
      }

      if (entry->priv->info->pixbuf)
      {
            pixbuf = entry->priv->info->pixbuf;
      }
      else
      {
            g_return_val_if_fail (entry->priv->info->pixbuf_filename, NULL);

            pixbuf = gdk_pixbuf_new_from_file (entry->priv->info->pixbuf_filename, NULL);

            if (!pixbuf)
            {
                  /* Corrupt pixbuf */
                  return NULL;
            }

            entry->priv->info->pixbuf = pixbuf;
      }


      /* Ensure the pixbuf is scaled correctly */
      if (gdk_pixbuf_get_width (pixbuf) > 16 ||
          gdk_pixbuf_get_height (pixbuf) > 16)
      {
            GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, 16, 16,
                                               GDK_INTERP_NEAREST);
            g_object_unref (G_OBJECT (pixbuf));
            pixbuf = scaled;
            entry->priv->info->pixbuf = pixbuf;
      }

      return pixbuf;
}

/** galeon_favicon_cache_entry_set_persistent:
 *  @entry: A #GaleonFaviconCacheEntry
 *  @persistent: Whether the cache entry should be preserved.
 * 
 *  If a cache entry is persistent, it will be preserved across
 *  galeon restarts. Non-persistent favicons won't be saved to disk, 
 *  and they will not be available on startup.
 */
void
galeon_favicon_cache_entry_set_persistent (GaleonFaviconCacheEntry *entry,
                                 gboolean persistent)
{
      g_return_if_fail (GALEON_IS_FAVICON_CACHE_ENTRY (entry));

      LOG ("galeon_favicon_cache_entry_set_persistent (%s, %d)",
           entry->priv->url, persistent);

      if (entry->priv->persistent != persistent)
      {
            entry->priv->persistent = persistent;
            g_object_notify (G_OBJECT (entry), "persistent");

            if (entry->priv->info)
            {
                  entry->priv->info->cache->priv->dirty = TRUE;
            }
      }
}

/** galeon_favicon_cache_entry_set_persistent:
 *  @entry: A #GaleonFaviconCacheEntry
 * 
 *  Get whether the cache entry is persistent (i.e. will it be
 *  available again after a restart)
 * 
 *  Return value: whether the cache entry is persistent
 */
gboolean
galeon_favicon_cache_entry_get_persistent (GaleonFaviconCacheEntry *entry)
{
      g_return_val_if_fail (GALEON_IS_FAVICON_CACHE_ENTRY (entry), FALSE);
      
      return entry->priv->persistent;
}

/* Set the pixbuf info for this cache entry */
static void
galeon_favicon_cache_entry_set_pixbuf_info (GaleonFaviconCacheEntry *entry,
                                  PixbufInfo *info)
{
      g_return_if_fail (GALEON_IS_FAVICON_CACHE_ENTRY (entry));

      if (info == entry->priv->info)
      {
            return;
      }

      if (info)
      {
            pixbuf_info_add_entry (info, entry);
            g_object_ref (G_OBJECT(entry));
      }

      if (entry->priv->info)
      {
            pixbuf_info_remove_entry (entry->priv->info, entry);
            g_object_unref (G_OBJECT(entry));
      }

      entry->priv->info = info;

      g_object_notify (G_OBJECT (entry), "pixbuf");
}

static void
galeon_favicon_cache_entry_set_property (GObject *object,
                               guint prop_id,
                               const GValue *value,
                               GParamSpec *pspec)
{
      GaleonFaviconCacheEntry *entry = GALEON_FAVICON_CACHE_ENTRY (object);

      switch (prop_id)
      {
      case PROP_PERSISTENT:
            galeon_favicon_cache_entry_set_persistent (entry,
                                             g_value_get_boolean (value));
            break;
      case PROP_PIXBUF:
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}

static void 
galeon_favicon_cache_entry_get_property (GObject *object,
                               guint prop_id,
                               GValue *value,
                               GParamSpec *pspec)
{
      GaleonFaviconCacheEntry *entry = GALEON_FAVICON_CACHE_ENTRY (object);

      switch (prop_id)
      {
      case PROP_PERSISTENT:
            g_value_set_boolean (value, entry->priv->persistent);
            break;
      case PROP_PIXBUF: {
            GdkPixbuf *pixbuf;

            pixbuf = galeon_favicon_cache_entry_get_pixbuf (entry);

            g_value_set_object (value, pixbuf);
            break;
      }
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}

static void
galeon_favicon_cache_entry_finalize (GObject *object)
{
      GaleonFaviconCacheEntry *entry = GALEON_FAVICON_CACHE_ENTRY (object);

      LOG ("galeon_favicon_cache_entry_finalize (%s)", entry->priv->url);

      galeon_favicon_cache_entry_set_pixbuf_info (entry, NULL);

      G_OBJECT_CLASS (galeon_favicon_cache_entry_parent_class)->finalize (object);
}

static void
galeon_favicon_cache_entry_init (GaleonFaviconCacheEntry *entry)
{
      entry->priv = GALEON_FAVICON_CACHE_ENTRY_GET_PRIVATE (entry);

}

static void
galeon_favicon_cache_entry_class_init (GaleonFaviconCacheEntryClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);

      object_class->finalize     = galeon_favicon_cache_entry_finalize;
      object_class->set_property = galeon_favicon_cache_entry_set_property;
      object_class->get_property = galeon_favicon_cache_entry_get_property;

      g_object_class_install_property (object_class,
                               PROP_PIXBUF,
                               g_param_spec_object ("pixbuf",
                                                "Pixbuf",
                                                "Pixbuf",
                                                GDK_TYPE_PIXBUF,
                                                G_PARAM_READABLE));
      g_object_class_install_property (object_class,
                               PROP_PERSISTENT,
                               g_param_spec_boolean ("persistent",
                                                 "Persistent",
                                                 "Persistent",
                                                 FALSE,
                                                 G_PARAM_READWRITE));

      g_type_class_add_private (klass, sizeof (GaleonFaviconCacheEntryPrivate));
}



/* ------------------------------------------------------------ 
 * GaleonFaviconCache
 * ------------------------------------------------------------ */

static void
cache_entry_weak_ref_cb (GaleonFaviconCache *cache,
                   GaleonFaviconCacheEntry *entry)
{
      g_hash_table_remove (cache->priv->url_to_entry, entry->priv->url);
}

static GaleonFaviconCacheEntry*
galeon_favicon_cache_create_entry (GaleonFaviconCache *cache,
                           const char *cache_url)
{
      GaleonFaviconCacheEntry *ret;

      g_return_val_if_fail (GALEON_IS_FAVICON_CACHE (cache), NULL);
      g_return_val_if_fail (cache_url, NULL);
      
      ret = g_object_new (GALEON_TYPE_FAVICON_CACHE_ENTRY, NULL);
      ret->priv->url = g_strdup (cache_url);

      g_hash_table_insert (cache->priv->url_to_entry,
                       g_strdup (cache_url), ret);

      g_object_weak_ref (G_OBJECT (ret), (GWeakNotify)cache_entry_weak_ref_cb, cache);

      return ret;
}

static void
galeon_favicon_cache_insert (GaleonFaviconCache *cache,
                       const char *url,
                       const char *pixbuf_location,
                       GdkPixbuf *pixbuf)
{
      GaleonFaviconCacheEntry *entry;
      PixbufInfo *info;

      LOG ("galeon_favicon_cache_insert (%s, %s, %p)", url, pixbuf_location, pixbuf);

      entry = galeon_favicon_cache_lookup (cache, url);
      if (!entry) return;

      info = g_hash_table_lookup (cache->priv->filename_to_pixbuf, pixbuf_location);
      if (info == NULL)
      {
            info = pixbuf_info_new (pixbuf_location, cache);
            g_hash_table_insert (cache->priv->filename_to_pixbuf,
                             g_strdup (pixbuf_location), info);

            info->on_disk = pixbuf ? FALSE : TRUE;
      }

      if (pixbuf)
      {
            pixbuf_info_set_pixbuf (info, pixbuf);
      }

      galeon_favicon_cache_entry_set_pixbuf_info (entry, info);

      /* The entry object holds a ref to itself while it has a pixbuf
       * attached to it */
      g_object_unref (entry);

      cache->priv->dirty = TRUE;
}

static void
save_item (const char *key, GaleonFaviconCacheEntry *entry, xmlTextWriterPtr writer)
{
      PixbufInfo *info = entry->priv->info;

      if (entry->priv->persistent && info && info->pixbuf_filename)
      {
            /* Save the image to disk */
            if (info->dirty && info->pixbuf)
            {
                  GError *err = NULL;
                  gdk_pixbuf_save (info->pixbuf, info->pixbuf_filename, 
                               "png", &err, NULL);
                  if (err)
                  {
                        g_error_free (err);
                        return;
                  }

                  info->dirty = FALSE;
                  info->on_disk = TRUE;
            }

            xmlTextWriterStartElement (writer, "entry");

            xmlTextWriterWriteAttribute (writer, "url", key);
            xmlTextWriterWriteAttribute (writer, "favicon",
                                   entry->priv->info->pixbuf_filename);

            xmlTextWriterEndElement (writer);
      }
}

static int
galeon_favicon_cache_save_to_file (GaleonFaviconCache *cache,
                           xmlTextWriterPtr writer)
{
      int ret;

      ret = xmlTextWriterStartDocument (writer, "1.0", NULL, NULL);
      if (ret < 0) return ret;
      ret = xmlTextWriterStartElement (writer, "GaleonFaviconCache");
      if (ret < 0) return ret;
      
      g_hash_table_foreach (cache->priv->url_to_entry, (GHFunc) save_item, writer);

      ret = xmlTextWriterEndElement (writer); /* root */
      if (ret < 0) return ret;

      ret = xmlTextWriterEndDocument (writer);
      if (ret < 0) return ret;
      
      return 0;
}

static gboolean
galeon_favicon_cache_ensure_directory (GaleonFaviconCache *cache)
{
      char *filename;
      int   fd;

      if (!g_file_test (cache->priv->directory, G_FILE_TEST_IS_DIR))
      {
            if (mkdir (cache->priv->directory, 0750) != 0)
            {
                  g_warning ("cannot create directory `%s': %s",
                           cache->priv->directory, g_strerror (errno));
                  return FALSE;
            }
      }

      filename = g_build_filename (cache->priv->directory, "CACHEDIR.TAG", NULL);
      fd = open (filename, O_RDWR | O_CREAT, 0660);
      if (fd != -1)
      {
            static const char tagHdr[] =
                  "Signature: 8a477f597d28d172789f06886806bc55\n"
                  "# This file is a cache directory tag created by Galeon.\n"
                  "# For information about cache directory tags, see:\n"
                  "#\thttp://www.brynosaurus.com/cachedir/\n";
            (void)write (fd, tagHdr, sizeof(tagHdr)-1);
            (void)close (fd);
      }
      g_free (filename);

      return TRUE;
}

static void
galeon_favicon_cache_sync_to_disc (GaleonFaviconCache *cache)
{
      xmlTextWriterPtr writer;
      gchar *tmpfile;

      if (!cache->priv->dirty)
            return;

      if (!galeon_favicon_cache_ensure_directory (cache))
            return;

      tmpfile = g_strconcat (cache->priv->filename, ".tmp", NULL);

      writer = xmlNewTextWriterFilename (tmpfile, 0);
      if (writer)
      {
            int ret;

            xmlTextWriterSetIndent (writer, 1);
            xmlTextWriterSetIndentString (writer, "  ");

            ret = galeon_favicon_cache_save_to_file (cache, writer);
            if (ret < 0)
            {
                  g_warning ("Failed writing to %s", cache->priv->filename);
            }
            else if (gul_general_switch_temp_file (cache->priv->filename, tmpfile))
            {
                  cache->priv->dirty = FALSE;
            }

            xmlFreeTextWriter (writer);
      }

      g_free (tmpfile);
}

static void
galeon_favicon_cache_sync_from_disc (GaleonFaviconCache *cache)
{
      xmlDocPtr doc;
      xmlNodePtr child;
      
      if (g_file_test (cache->priv->filename, G_FILE_TEST_EXISTS) == FALSE)
            return;

      doc = xmlParseFile (cache->priv->filename);

      if (doc == NULL)
            return;

      for (child = doc->children->children; child != NULL; child = child->next)
      {
            char *url = xmlGetProp (child, "url");
            char *favicon = xmlGetProp (child, "favicon");

            if (url && favicon)
            {
                  galeon_favicon_cache_insert (cache, url, favicon, NULL);
            }

            g_free (url);
            g_free (favicon);
      }

      xmlFreeDoc (doc);
}

static gboolean
galeon_favicon_cache_timeout_cb (GaleonFaviconCache *cache)
{
      galeon_favicon_cache_sync_to_disc (cache);
      
      return TRUE;
}

static char *
galeon_favicon_cache_url (const char *url)
{
      GnomeVFSURI *uri;
      char *result, *clean_url;
      int clean_url_len;

      if (url == NULL)
      {
            return NULL;
      }

      uri = gnome_vfs_uri_new (url);
      if (uri == NULL)
      {
            return NULL;
      }

      clean_url = gnome_vfs_uri_to_string (uri,
                                   GNOME_VFS_URI_HIDE_USER_NAME |
                                   GNOME_VFS_URI_HIDE_PASSWORD |
                                   GNOME_VFS_URI_HIDE_FRAGMENT_IDENTIFIER);

      clean_url_len = strlen (clean_url);
      if (clean_url[clean_url_len - 1] == '/')
      {
            result = g_strndup (clean_url, clean_url_len - 1);
            g_free (clean_url);
      }
      else
      {
            result = clean_url;
      }

      gnome_vfs_uri_unref (uri);

      return result;
}


static char *
galeon_favicon_cache_dest (GaleonFaviconCache *cache, const char *url)
{
      char *clean_url = galeon_favicon_cache_url (url);
      char *slashpos, *dest;

      if (clean_url == NULL)
      {
            return NULL;
      }

      while ((slashpos = strstr (clean_url, "/")) != NULL)
      {
            *slashpos = '_';
      }
      
      dest = g_build_filename (cache->priv->directory, clean_url, NULL);
      
      g_free (clean_url);

      return dest;
}

static void
favicon_download_completed_cb (GaleonEmbedPersist *persist,
                         GaleonFaviconCache *cache)
{
      const char *url;
      char *favicon_url;
      char *dest;
      GdkPixbufLoader *loader;
      GdkPixbuf *pixbuf;
      GError *error = NULL;

      loader = g_object_steal_data (G_OBJECT (persist), "pixbuf-loader");

      if (!gdk_pixbuf_loader_close (loader, &error))
      {
            LOG("error=%s", error->message);
            g_error_free (error);
            
            g_object_unref (loader);
            return;
      }

      pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
      if (!pixbuf)
      {
            g_object_unref (loader);
            return;
      }
      
      url    = g_object_get_data (G_OBJECT (persist), "url");
      g_object_get (persist, "source", &favicon_url, NULL);

      dest = galeon_favicon_cache_dest (cache, favicon_url);

      if (dest)
      {
            galeon_favicon_cache_insert (cache, url, dest, pixbuf);
      }

      g_object_unref (loader);
      g_free (favicon_url);
}

static gboolean
persist_stream_cb (GaleonEmbedPersist *persist, const char *buffer,
               guint len, gpointer data)
{
      GdkPixbufLoader *loader = data;
      GError *error = NULL;
      
      if (!gdk_pixbuf_loader_write (loader, buffer, len, &error))
      {
            LOG("error=%s", error->message);
            g_error_free (error);

            return FALSE;
      }

      return TRUE;
}

static void
free_pixbuf_loader (gpointer data)
{
      GdkPixbufLoader *loader = data;
      gdk_pixbuf_loader_close (loader, NULL);
      g_object_unref (loader);
}



/** galeon_favicon_cache_insert_from_url:
 *  @cache: A #GaleonFaviconCache
 *  @url: a url to lookup in the cache
 *  @favicon_url: The corresponding favicon url
 *
 *  This sets the favicon url for the page. The image is looked up
 *  immediately, via the #GaleonEmbedPersist object.
 */
void
galeon_favicon_cache_insert_from_url (GaleonFaviconCache *cache,
                              const char *url,
                              const char *favicon_url)
{
      GaleonEmbedPersist *persist;
      GdkPixbufLoader *loader;

      g_return_if_fail (GALEON_IS_FAVICON_CACHE (cache));
      g_return_if_fail (url != NULL);
      g_return_if_fail (favicon_url != NULL);

      LOG ("galeon_favicon_cache_insert_from_url(%s, %s)", url, favicon_url);

      persist = galeon_embed_persist_new (NULL);

      galeon_embed_persist_set_max_size (persist, 100);
      galeon_embed_persist_set_source   (persist, favicon_url);

      g_object_set_data_full (G_OBJECT (persist), "url", g_strdup (url), g_free);

      loader = gdk_pixbuf_loader_new();
      g_object_set_data_full (G_OBJECT (persist), "pixbuf-loader", 
                        loader, free_pixbuf_loader);

      g_signal_connect_object (G_OBJECT (persist),
                         "completed",
                         G_CALLBACK (favicon_download_completed_cb),
                         cache, 0);

      galeon_embed_persist_stream (persist, persist_stream_cb, loader);

      g_object_unref (persist);
}


/** galeon_favicon_cache_lookup:
 *  @cache: A #GaleonFaviconCache
 *  @url: a url to lookup in the cache
 *
 *  Looks up a url in the cache returning a #GaleonFaviconCacheEntry.
 *  the #GaleonFaviconCacheEntry has its reference count incrememted,
 *  so you must call g_object_unref() when you are no longer interested
 *  in the cache entry.
 *
 *  Return value: A #GaleonFaviconCacheEntry (remeber to unref() it)
 */
GaleonFaviconCacheEntry *
galeon_favicon_cache_lookup (GaleonFaviconCache *cache,
                       const char *url)
{
      char *cache_url;
      GaleonFaviconCacheEntry *ret;

      LOG ("galeon_favicon_cache_lookup (%s)", url);

      g_return_val_if_fail (GALEON_IS_FAVICON_CACHE (cache), NULL);

      if (url == NULL || *url == '\0')
      {
            return NULL;
      }

      cache_url = galeon_favicon_cache_url (url);
      if (!cache_url)
      {
            return NULL;
      }

      ret = g_hash_table_lookup (cache->priv->url_to_entry, cache_url);

      if (!ret)
      {
            LOG ("Creating entry: %s", cache_url);
            ret = galeon_favicon_cache_create_entry (cache, cache_url);
      }
      else
      {
            LOG ("Found entry: %s", cache_url);

            g_object_ref (ret);
      }

      g_free (cache_url);

      return ret;
}


static void
unlink_non_persistent_files (const char *key, PixbufInfo *info, gpointer dummy)
{
      GList *l;
      gboolean persistent = FALSE;

      if (!info->on_disk)
      {
            return;
      }

      for (l = info->entries; l ; l = l->next)
      {
            GaleonFaviconCacheEntry *entry = l->data;

            if (entry && entry->priv->persistent)
            {
                  persistent = TRUE;
                  break;
            }
      }
      
      if (!persistent)
      {
            LOG ("Unlinking %s", info->pixbuf_filename);

            unlink (info->pixbuf_filename);
      }
}

static void
remove_weak_ref (const char *key, GaleonFaviconCacheEntry *entry, gpointer cache)
{
      g_object_weak_unref (G_OBJECT (entry), (GWeakNotify)cache_entry_weak_ref_cb, cache);
}


static void
galeon_favicon_cache_finalize (GObject *object)
{
      GaleonFaviconCache *cache = GALEON_FAVICON_CACHE (object);;

      g_source_remove (cache->priv->timeout);

      galeon_favicon_cache_sync_to_disc (cache);

      g_hash_table_foreach (cache->priv->filename_to_pixbuf,
                        (GHFunc)unlink_non_persistent_files, NULL);
      
      g_hash_table_foreach (cache->priv->url_to_entry,
                        (GHFunc)remove_weak_ref, cache);

      g_hash_table_destroy (cache->priv->filename_to_pixbuf);
      g_hash_table_destroy (cache->priv->url_to_entry);

      g_free (cache->priv->filename);
      g_free (cache->priv->directory);

      G_OBJECT_CLASS (galeon_favicon_cache_parent_class)->finalize (object);
}

static void
galeon_favicon_cache_init (GaleonFaviconCache *cache)
{
      cache->priv = GALEON_FAVICON_CACHE_GET_PRIVATE (cache);

      cache->priv->url_to_entry = g_hash_table_new_full (g_str_hash,
                                             g_str_equal,
                                             (GDestroyNotify) g_free,
                                             NULL);

      cache->priv->filename_to_pixbuf = g_hash_table_new_full (g_str_hash,
                                                 g_str_equal,
                                                 (GDestroyNotify)g_free,
                                                 (GDestroyNotify)pixbuf_info_free);

      cache->priv->filename  = g_build_filename (g_get_home_dir (),
                                           GALEON_DIR,
                                           "favicon_cache.xml",
                                           NULL);
      cache->priv->directory = g_build_filename (g_get_home_dir (),
                                       GALEON_DIR,
                                       "favicon_cache/",
                                       NULL);

      cache->priv->dirty = FALSE;
      
      START_PROFILER("galeon_favicon_cache_sync_from_disc");
      galeon_favicon_cache_sync_from_disc (cache);
      galeon_favicon_cache_ensure_directory (cache);
      STOP_PROFILER("galeon_favicon_cache_sync_from_disc");

      /* sync to disc every 10 minutes */
      cache->priv->timeout = g_timeout_add (10 * 60 * 1000,
                                    (GSourceFunc) galeon_favicon_cache_timeout_cb,
                                    cache);
}

static void
galeon_favicon_cache_class_init (GaleonFaviconCacheClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);

      object_class->finalize = galeon_favicon_cache_finalize;

      g_type_class_add_private (klass, sizeof (GaleonFaviconCachePrivate));
}



GaleonFaviconCache *
galeon_favicon_cache_new (void)
{
      GaleonFaviconCache *cache;

      cache = GALEON_FAVICON_CACHE (g_object_new (GALEON_TYPE_FAVICON_CACHE, NULL));

      return cache;
}


Generated by  Doxygen 1.6.0   Back to index