summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--ChangeLog.pre-2-1023
-rw-r--r--ChangeLog.pre-2-823
-rw-r--r--docs/iconcache.txt70
-rw-r--r--gtk/gtkiconcache.c169
-rw-r--r--gtk/gtkiconcache.h19
-rw-r--r--gtk/gtkicontheme.c31
-rw-r--r--gtk/updateiconcache.c417
8 files changed, 723 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index f3b973b152..77366d3afd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2005-03-15 Anders Carlsson <andersca@imendio.com>
+
+ * docs/iconcache.txt:
+ Update spec.
+
+ * gtk/gtkiconcache.c: (find_image_offset),
+ (_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
+ (_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
+ * gtk/gtkiconcache.h:
+ Update to be able to fetch pixbuf data and icon metadata.
+
+ * gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
+ (icon_info_ensure_scale_and_pixbuf):
+ Use new cache functions.
+
+ * gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
+ (maybe_cache_image_data), (scan_directory), (write_pixdata),
+ (get_image_meta_data_size), (get_image_pixel_data_size),
+ (get_image_data_size), (get_single_node_size), (get_bucket_size),
+ (write_bucket), (main):
+ Update to write pixbuf data as well as information from .icon
+ files.
+
2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index f3b973b152..77366d3afd 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,26 @@
+2005-03-15 Anders Carlsson <andersca@imendio.com>
+
+ * docs/iconcache.txt:
+ Update spec.
+
+ * gtk/gtkiconcache.c: (find_image_offset),
+ (_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
+ (_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
+ * gtk/gtkiconcache.h:
+ Update to be able to fetch pixbuf data and icon metadata.
+
+ * gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
+ (icon_info_ensure_scale_and_pixbuf):
+ Use new cache functions.
+
+ * gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
+ (maybe_cache_image_data), (scan_directory), (write_pixdata),
+ (get_image_meta_data_size), (get_image_pixel_data_size),
+ (get_image_data_size), (get_single_node_size), (get_bucket_size),
+ (write_bucket), (main):
+ Update to write pixbuf data as well as information from .icon
+ files.
+
2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index f3b973b152..77366d3afd 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,26 @@
+2005-03-15 Anders Carlsson <andersca@imendio.com>
+
+ * docs/iconcache.txt:
+ Update spec.
+
+ * gtk/gtkiconcache.c: (find_image_offset),
+ (_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
+ (_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
+ * gtk/gtkiconcache.h:
+ Update to be able to fetch pixbuf data and icon metadata.
+
+ * gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
+ (icon_info_ensure_scale_and_pixbuf):
+ Use new cache functions.
+
+ * gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
+ (maybe_cache_image_data), (scan_directory), (write_pixdata),
+ (get_image_meta_data_size), (get_image_pixel_data_size),
+ (get_image_data_size), (get_single_node_size), (get_bucket_size),
+ (write_bucket), (main):
+ Update to write pixbuf data as well as information from .icon
+ files.
+
2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New
diff --git a/docs/iconcache.txt b/docs/iconcache.txt
index 2cae3e0a43..b2d8f8f80f 100644
--- a/docs/iconcache.txt
+++ b/docs/iconcache.txt
@@ -41,32 +41,32 @@ Regards, Matthias Clasen
The cache file format:
Header:
-2 CARD16 MAJOR_VERSION 1
-2 CARD16 MINOR_VERSION 0
-4 CARD32 HASH_OFFSET
-4 CARD32 DIRECTORY_LIST_OFFSET
+2 CARD16 MAJOR_VERSION 1
+2 CARD16 MINOR_VERSION 0
+4 CARD32 HASH_OFFSET
+4 CARD32 DIRECTORY_LIST_OFFSET
DirectoryList:
-4 CARD32 N_DIRECTORIES
-4*N_DIRECTORIES CARD32 DIRECTORY_OFFSET
+4 CARD32 N_DIRECTORIES
+4*N_DIRECTORIES CARD32 DIRECTORY_OFFSET
Hash:
-4 CARD32 N_BUCKETS
-4*N_BUCKETS CARD32 ICON_OFFSET
+4 CARD32 N_BUCKETS
+4*N_BUCKETS CARD32 ICON_OFFSET
Icon:
-4 CARD32 CHAIN_OFFSET
-4 CARD32 NAME_OFFSET
-4 CARD32 IMAGE_LIST_OFFSET
+4 CARD32 CHAIN_OFFSET
+4 CARD32 NAME_OFFSET
+4 CARD32 IMAGE_LIST_OFFSET
ImageList:
-4 CARD32 N_IMAGES
-8*N_IMAGES Image IMAGES
+4 CARD32 N_IMAGES
+8*N_IMAGES Image IMAGES
Image:
-2 CARD16 DIRECTORY_INDEX
-2 ICON_FLAGS FLAGS
-4 CARD32 IMAGE_DATA_OFFSET
+2 CARD16 DIRECTORY_INDEX
+2 ICON_FLAGS FLAGS
+4 CARD32 IMAGE_DATA_OFFSET
ICON_FLAGS
HAS_SUFFIX_PNG 1
@@ -74,6 +74,44 @@ HAS_SUFFIX_XPM 2
HAS_SUFFIX_SVG 4
HAS_ICON_FILE 8
+ImageData:
+4 CARD32 IMAGE_PIXEL_DATA_OFFSET
+4 CARD32 IMAGE_META_DATA_OFFSET
+
+4 CARD32 IMAGE_PIXEL_DATA_TYPE
+4 CARD32 IMAGE_PIXEL_DATA_LENGTH
+N/A N/A PIXEL_DATA
+
+IMAGE_PIXEL_DATA_TYPE
+0 GdkPixdata format
+
+MetaData:
+4 CARD32 EMBEDDED_RECT_OFFSET
+4 CARD32 ATTACH_POINT_LIST_OFFSET
+4 CARD32 DISPLAY_NAME_LIST_OFFSET
+
+EmbeddedRect:
+2 CARD16 X0
+2 CARD16 Y0
+2 CARD16 X1
+2 CARD16 Y1
+
+AttachPointList:
+4 CARD32 N_ATTACH_POINTS
+4*N_ATTACH_POINTS AttachPoint
+
+AttachPoint:
+2 CARD16 X
+2 CARD16 Y
+
+DisplayNameList:
+4 CARD32 N_DISPLAY_NAMES
+4*N_DISPLAY_NAMES DisplayName
+
+DisplayName:
+4 CARD32 DISPLAY_LANG_OFFSET
+4 CARD32 DISPLAY_NAME_OFFSET
+
Notes:
diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c
index fc44d036de..5849549ee3 100644
--- a/gtk/gtkiconcache.c
+++ b/gtk/gtkiconcache.c
@@ -21,6 +21,7 @@
#include "gtkdebug.h"
#include "gtkiconcache.h"
#include <glib/gstdio.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
@@ -233,9 +234,9 @@ icon_name_hash (gconstpointer key)
}
gint
-_gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
- const gchar *icon_name,
- const gchar *directory)
+find_image_offset (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory)
{
guint32 hash_offset;
guint32 n_buckets;
@@ -265,8 +266,9 @@ _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
chain_offset = GET_UINT32 (cache->buffer, chain_offset);
}
- if (!found)
+ if (!found) {
return 0;
+ }
/* We've found an icon list, now check if we have the right icon in it */
directory_index = get_directory_index (cache, directory);
@@ -276,13 +278,28 @@ _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
for (i = 0; i < n_images; i++)
{
if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i) ==
- directory_index)
- return GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i + 2);
+ directory_index)
+ return image_list_offset + 4 + 8 * i;
}
-
+
return 0;
}
+gint
+_gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory)
+{
+ guint32 image_offset;
+
+ image_offset = find_image_offset (cache, icon_name, directory);
+
+ if (!image_offset)
+ return 0;
+
+ return GET_UINT16 (cache->buffer, image_offset + 2);
+}
+
void
_gtk_icon_cache_add_icons (GtkIconCache *cache,
const gchar *directory,
@@ -301,7 +318,7 @@ _gtk_icon_cache_add_icons (GtkIconCache *cache,
hash_offset = GET_UINT32 (cache->buffer, 4);
n_buckets = GET_UINT32 (cache->buffer, hash_offset);
-
+
for (i = 0; i < n_buckets; i++)
{
chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * i);
@@ -354,4 +371,140 @@ _gtk_icon_cache_has_icon (GtkIconCache *cache,
return FALSE;
}
+GdkPixbuf *
+_gtk_icon_cache_get_icon (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory)
+{
+ guint32 offset, image_data_offset, pixel_data_offset;
+ guint32 length, type;
+ GdkPixbuf *pixbuf;
+ GdkPixdata pixdata;
+ GError *error = NULL;
+
+ offset = find_image_offset (cache, icon_name, directory);
+
+ image_data_offset = GET_UINT32 (cache->buffer, offset + 4);
+
+ if (!image_data_offset)
+ return NULL;
+
+ pixel_data_offset = GET_UINT32 (cache->buffer, image_data_offset);
+
+ type = GET_UINT32 (cache->buffer, pixel_data_offset);
+
+ if (type != 0)
+ {
+ GTK_NOTE (ICONTHEME,
+ g_print ("invalid pixel data type %d\n", type));
+ return NULL;
+ }
+
+ length = GET_UINT32 (cache->buffer, pixel_data_offset + 4);
+
+ if (!gdk_pixdata_deserialize (&pixdata, length,
+ cache->buffer + pixel_data_offset + 8,
+ &error))
+ {
+ GTK_NOTE (ICONTHEME,
+ g_print ("could not deserialize data: %s\n", error->message));
+ g_error_free (error);
+
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, &error);
+
+ if (!pixbuf)
+ {
+ GTK_NOTE (ICONTHEME,
+ g_print ("could not convert pixdata to pixbuf: %s\n", error->message));
+ g_error_free (error);
+
+ return NULL;
+ }
+
+ return pixbuf;
+}
+
+GtkIconData *
+_gtk_icon_cache_get_icon_data (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory)
+{
+ guint32 offset, image_data_offset, meta_data_offset;
+ GtkIconData *data;
+ int i;
+
+ offset = find_image_offset (cache, icon_name, directory);
+ if (!offset)
+ return NULL;
+
+ image_data_offset = GET_UINT32 (cache->buffer, offset + 4);
+ if (!image_data_offset)
+ return NULL;
+
+ meta_data_offset = GET_UINT32 (cache->buffer, image_data_offset + 4);
+
+ if (!meta_data_offset)
+ return NULL;
+
+ data = g_new0 (GtkIconData, 1);
+
+ offset = GET_UINT32 (cache->buffer, meta_data_offset);
+ if (offset)
+ {
+ data->has_embedded_rect = TRUE;
+ data->x0 = GET_UINT16 (cache->buffer, offset);
+ data->y0 = GET_UINT16 (cache->buffer, offset + 2);
+ data->x1 = GET_UINT16 (cache->buffer, offset + 4);
+ data->y1 = GET_UINT16 (cache->buffer, offset + 6);
+ }
+
+ offset = GET_UINT32 (cache->buffer, meta_data_offset + 4);
+ if (offset)
+ {
+ data->n_attach_points = GET_UINT32 (cache->buffer, offset);
+ data->attach_points = g_new (GdkPoint, data->n_attach_points);
+ for (i = 0; i < data->n_attach_points; i++)
+ {
+ data->attach_points[i].x = GET_UINT16 (cache->buffer, offset + 4 + 4 * i);
+ data->attach_points[i].y = GET_UINT16 (cache->buffer, offset + 4 + 4 * i + 2);
+ }
+ }
+
+ offset = GET_UINT32 (cache->buffer, meta_data_offset + 8);
+ if (offset)
+ {
+ gint n_names;
+ gchar *lang, *name;
+ gchar **langs;
+ GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ n_names = GET_UINT32 (cache->buffer, offset);
+
+ for (i = 0; i < n_names; i++)
+ {
+ lang = cache->buffer + GET_UINT32 (cache->buffer, offset + 4 + 8 * i);
+ name = cache->buffer + GET_UINT32 (cache->buffer, offset + 4 + 8 * i + 4);
+
+ g_hash_table_insert (table, lang, name);
+ }
+
+ langs = (gchar **)g_get_language_names ();
+ for (i = 0; langs[i]; i++)
+ {
+ name = g_hash_table_lookup (table, langs[i]);
+ if (name)
+ {
+ data->display_name = g_strdup (name);
+ break;
+ }
+ }
+
+ g_hash_table_destroy (table);
+ }
+
+ return data;
+}
diff --git a/gtk/gtkiconcache.h b/gtk/gtkiconcache.h
index 010ebfe939..134a3ab317 100644
--- a/gtk/gtkiconcache.h
+++ b/gtk/gtkiconcache.h
@@ -20,8 +20,21 @@
#define __GTK_ICON_CACHE_H__
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdk.h>
typedef struct _GtkIconCache GtkIconCache;
+typedef struct _GtkIconData GtkIconData;
+
+struct _GtkIconData
+{
+ gboolean has_embedded_rect;
+ gint x0, y0, x1, y1;
+
+ GdkPoint *attach_points;
+ gint n_attach_points;
+
+ gchar *display_name;
+};
GtkIconCache *_gtk_icon_cache_new_for_path (const gchar *path);
gboolean _gtk_icon_cache_has_directory (GtkIconCache *cache,
@@ -35,6 +48,12 @@ void _gtk_icon_cache_add_icons (GtkIconCache *cache,
gint _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory);
+GdkPixbuf *_gtk_icon_cache_get_icon (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory);
+GtkIconData *_gtk_icon_cache_get_icon_data (GtkIconCache *cache,
+ const gchar *icon_name,
+ const gchar *directory);
GtkIconCache *_gtk_icon_cache_ref (GtkIconCache *cache);
void _gtk_icon_cache_unref (GtkIconCache *cache);
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 06740a7c42..b5000fd5c7 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -47,8 +47,6 @@
#define DEFAULT_THEME_NAME "hicolor"
-typedef struct _GtkIconData GtkIconData;
-
typedef enum
{
ICON_THEME_DIR_FIXED,
@@ -113,6 +111,9 @@ struct _GtkIconInfo
#endif
GdkPixbuf *builtin_pixbuf;
+ /* Cache pixbuf (if there is any) */
+ GdkPixbuf *cache_pixbuf;
+
GtkIconData *data;
/* Information about the directory where
@@ -151,17 +152,6 @@ typedef struct
GList *dirs;
} IconTheme;
-struct _GtkIconData
-{
- gboolean has_embedded_rect;
- gint x0, y0, x1, y1;
-
- GdkPoint *attach_points;
- gint n_attach_points;
-
- gchar *display_name;
-};
-
typedef struct
{
IconThemeDirType type;
@@ -1901,7 +1891,9 @@ theme_lookup_icon (IconTheme *theme,
if (min_dir->icon_data != NULL)
icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
-
+ else
+ icon_info->data = _gtk_icon_cache_get_icon_data (min_dir->cache, icon_name, min_dir->subdir);
+
if (icon_info->data == NULL &&
min_dir->cache && has_icon_file)
{
@@ -1923,6 +1915,12 @@ theme_lookup_icon (IconTheme *theme,
g_free (icon_file_path);
}
+ if (min_dir->cache)
+ {
+ icon_info->cache_pixbuf = _gtk_icon_cache_get_icon (min_dir->cache, icon_name,
+ min_dir->subdir);
+ }
+
icon_info->dir_type = min_dir->type;
icon_info->dir_size = min_dir->size;
icon_info->threshold = min_dir->threshold;
@@ -2334,6 +2332,8 @@ gtk_icon_info_free (GtkIconInfo *icon_info)
g_object_unref (icon_info->builtin_pixbuf);
if (icon_info->pixbuf)
g_object_unref (icon_info->pixbuf);
+ if (icon_info->cache_pixbuf)
+ g_object_unref (icon_info->cache_pixbuf);
g_free (icon_info);
}
@@ -2519,8 +2519,11 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info,
*/
if (icon_info->builtin_pixbuf)
source_pixbuf = g_object_ref (icon_info->builtin_pixbuf);
+ else if (icon_info->cache_pixbuf)
+ source_pixbuf = g_object_ref (icon_info->cache_pixbuf);
else
{
+
source_pixbuf = gdk_pixbuf_new_from_file (icon_info->filename,
&icon_info->load_error);
if (!source_pixbuf)
diff --git a/gtk/updateiconcache.c b/gtk/updateiconcache.c
index 076c10219d..8063f467a0 100644
--- a/gtk/updateiconcache.c
+++ b/gtk/updateiconcache.c
@@ -30,6 +30,7 @@
#include <glib.h>
#include <glib/gstdio.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
static gboolean force_update = FALSE;
static gboolean quiet = FALSE;
@@ -41,6 +42,8 @@ static gboolean quiet = FALSE;
#define HAS_SUFFIX_PNG (1 << 2)
#define HAS_ICON_FILE (1 << 3)
+#define CAN_CACHE_IMAGE_DATA(flags) (((flags) & HAS_SUFFIX_PNG) || ((flags) & HAS_SUFFIX_XPM))
+
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
#define HASH_OFFSET 12
@@ -82,6 +85,18 @@ typedef struct
{
int flags;
int dir_index;
+
+ gboolean has_pixdata;
+ GdkPixdata pixdata;
+
+ int has_embedded_rect;
+ int x0, y0, x1, y1;
+
+ int n_attach_points;
+ int *attach_points;
+
+ int n_display_names;
+ char **display_names;
} Image;
static gboolean
@@ -96,6 +111,8 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
{
g_free (key);
g_free (image);
+ g_free (image->attach_points);
+ g_strfreev (image->display_names);
return TRUE;
}
@@ -113,6 +130,132 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
return TRUE;
}
+static void
+load_icon_data (Image *image, const char *path)
+{
+ GKeyFile *icon_file;
+ char **split;
+ gsize length;
+ char *str;
+ char *split_point;
+ int i;
+ gint *ivalues;
+ GError *error = NULL;
+ gchar **keys;
+ gsize n_keys;
+
+ icon_file = g_key_file_new ();
+ g_key_file_set_list_separator (icon_file, ',');
+ g_key_file_load_from_file (icon_file, path, G_KEY_FILE_KEEP_TRANSLATIONS, &error);
+ if (error)
+ {
+ g_error_free (error);
+ return;
+ }
+
+ ivalues = g_key_file_get_integer_list (icon_file,
+ "Icon Data", "EmbeddedTextRectangle",
+ &length, NULL);
+ if (ivalues)
+ {
+ if (length == 4)
+ {
+ image->has_embedded_rect = TRUE;
+ image->x0 = ivalues[0];
+ image->y0 = ivalues[1];
+ image->x1 = ivalues[2];
+ image->y1 = ivalues[3];
+ }
+
+ g_free (ivalues);
+ }
+
+ str = g_key_file_get_string (icon_file, "Icon Data", "AttachPoints", NULL);
+ if (str)
+ {
+ split = g_strsplit (str, "|", -1);
+
+ image->n_attach_points = g_strv_length (split);
+ image->attach_points = g_new (int, 2 * image->n_attach_points);
+
+ i = 0;
+ while (split[i] != NULL && i < image->n_attach_points)
+ {
+ split_point = strchr (split[i], ',');
+ if (split_point)
+ {
+ *split_point = 0;
+ split_point++;
+ image->attach_points[2 * i] = atoi (split[i]);
+ image->attach_points[2 * i + 1] = atoi (split_point);
+ }
+ i++;
+ }
+
+ g_strfreev (split);
+ g_free (str);
+ }
+
+ keys = g_key_file_get_keys (icon_file, "Icon Data", &n_keys, &error);
+ image->display_names = g_new0 (gchar *, 2 * n_keys + 1);
+ image->n_display_names = 0;
+
+ for (i = 0; i < n_keys; i++)
+ {
+ gchar *lang, *name;
+
+ if (g_str_has_prefix (keys[i], "DisplayName"))
+ {
+ gchar *open, *close = NULL;
+
+ open = strchr (keys[i], '[');
+
+ if (open)
+ close = strchr (open, ']');
+
+ if (open && close)
+ {
+ lang = g_strndup (open + 1, close - open - 1);
+ name = g_key_file_get_locale_string (icon_file,
+ "Icon Data", "DisplayName",
+ lang, NULL);
+ }
+ else
+ {
+ lang = g_strdup ("C");
+ name = g_key_file_get_string (icon_file,
+ "Icon Data", "DisplayName",
+ NULL);
+ }
+
+ image->display_names[2 * image->n_display_names] = lang;
+ image->display_names[2 * image->n_display_names + 1] = name;
+ image->n_display_names++;
+ }
+ }
+
+ g_strfreev (keys);
+
+ g_key_file_free (icon_file);
+}
+
+static void
+maybe_cache_image_data (Image *image, const gchar *path)
+{
+ if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->has_pixdata)
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+
+ if (pixbuf)
+ {
+ image->has_pixdata = TRUE;
+ gdk_pixdata_from_pixbuf (&image->pixdata, pixbuf, FALSE);
+ }
+ }
+}
+
GList *
scan_directory (const gchar *base_path,
const gchar *subdir,
@@ -163,8 +306,7 @@ scan_directory (const gchar *base_path,
}
retval = g_file_test (path, G_FILE_TEST_IS_REGULAR);
- g_free (path);
-
+
if (retval)
{
if (g_str_has_suffix (name, ".png"))
@@ -185,7 +327,10 @@ scan_directory (const gchar *base_path,
image = g_hash_table_lookup (dir_hash, basename);
if (image)
- image->flags |= flags;
+ {
+ image->flags |= flags;
+ maybe_cache_image_data (image, path);
+ }
else
{
if (!dir_added)
@@ -203,12 +348,19 @@ scan_directory (const gchar *base_path,
image = g_new0 (Image, 1);
image->flags = flags;
image->dir_index = dir_index;
-
+ maybe_cache_image_data (image, path);
+
g_hash_table_insert (dir_hash, g_strdup (basename), image);
}
+ if (g_str_has_suffix (name, ".icon"))
+ load_icon_data (image, path);
+
g_free (basename);
}
+
+ g_free (path);
+
}
g_dir_close (dir);
@@ -313,6 +465,34 @@ write_card32 (FILE *cache, guint32 n)
return i == 1;
}
+
+gboolean
+write_pixdata (FILE *cache, GdkPixdata *pixdata)
+{
+ guint8 *s;
+ int len;
+ int i;
+
+
+ /* Type 0 is GdkPixdata */
+ if (!write_card32 (cache, 0))
+ return FALSE;
+
+ s = gdk_pixdata_serialize (pixdata, &len);
+
+ if (!write_card32 (cache, len))
+ {
+ g_free (s);
+ return FALSE;
+ }
+
+ i = fwrite (s, len, 1, cache);
+
+ g_free (s);
+
+ return i == 1;
+}
+
static gboolean
write_header (FILE *cache, guint32 dir_list_offset)
{
@@ -322,11 +502,64 @@ write_header (FILE *cache, guint32 dir_list_offset)
write_card32 (cache, dir_list_offset));
}
+guint
+get_image_meta_data_size (Image *image)
+{
+ gint i;
+ guint len = 0;
+
+ if (image->has_embedded_rect ||
+ image->attach_points > 0 ||
+ image->n_display_names > 0)
+ len += 12;
+
+ if (image->has_embedded_rect)
+ len += 8;
+
+ if (image->n_attach_points > 0)
+ len += 4 + image->n_attach_points * 4;
+
+ if (image->n_display_names > 0)
+ {
+ len += 4 + 8 * image->n_display_names;
+
+ for (i = 0; image->display_names[i]; i++)
+ len += ALIGN_VALUE (strlen (image->display_names[i]) + 1, 4);
+ }
+
+ return len;
+}
+
+guint
+get_image_pixel_data_size (Image *image)
+{
+ if (image->has_pixdata)
+ return image->pixdata.length + 8;
+
+ return 0;
+}
guint
-get_single_node_size (HashNode *node)
+get_image_data_size (Image *image)
+{
+ guint len;
+
+ len = 0;
+
+ len += get_image_pixel_data_size (image);
+ len += get_image_meta_data_size (image);
+
+ if (len > 0)
+ len += 8;
+
+ return len;
+}
+
+guint
+get_single_node_size (HashNode *node, gboolean include_image_data)
{
int len = 0;
+ GList *list;
/* Node pointers */
len += 12;
@@ -336,7 +569,16 @@ get_single_node_size (HashNode *node)
/* Image list */
len += 4 + g_list_length (node->image_list) * 8;
-
+
+ /* Image data */
+ if (include_image_data)
+ for (list = node->image_list; list; list = list->next)
+ {
+ Image *image = list->data;
+
+ len += get_image_data_size (image);
+ }
+
return len;
}
@@ -347,7 +589,7 @@ get_bucket_size (HashNode *node)
while (node)
{
- len += get_single_node_size (node);
+ len += get_single_node_size (node, TRUE);
node = node->next;
}
@@ -360,8 +602,11 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
{
while (node != NULL)
{
- int next_offset = *offset + get_single_node_size (node);
- int i, len;
+ int next_offset = *offset + get_single_node_size (node, TRUE);
+ int image_data_offset = *offset + get_single_node_size (node, FALSE);
+ int data_offset;
+ int tmp;
+ int i, j, len;
GList *list;
/* Chain offset */
@@ -381,7 +626,8 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
return FALSE;
/* Image list offset */
- if (!write_card32 (cache, *offset + 12 + ALIGN_VALUE (strlen (node->name) + 1, 4)))
+ tmp = *offset + 12 + ALIGN_VALUE (strlen (node->name) + 1, 4);
+ if (!write_card32 (cache, tmp))
return FALSE;
/* Icon name */
@@ -393,10 +639,15 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
if (!write_card32 (cache, len))
return FALSE;
+ /* Image data goes right after the image list */
+ tmp += 4 + len * 8;
+
list = node->image_list;
+ data_offset = image_data_offset;
for (i = 0; i < len; i++)
{
Image *image = list->data;
+ int image_data_size = get_image_data_size (image);
/* Directory index */
if (!write_card16 (cache, image->dir_index))
@@ -405,14 +656,151 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
/* Flags */
if (!write_card16 (cache, image->flags))
return FALSE;
-
+
/* Image data offset */
- if (!write_card32 (cache, 0))
- return FALSE;
-
+ if (image_data_size > 0)
+ {
+ if (!write_card32 (cache, data_offset))
+ return FALSE;
+ data_offset += image_data_size;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
list = list->next;
}
+ /* Now write the image data */
+ list = node->image_list;
+ for (i = 0; i < len; i++, list = list->next)
+ {
+ Image *image = list->data;
+ int pixel_data_size = get_image_pixel_data_size (image);
+ int meta_data_size = get_image_meta_data_size (image);
+
+ if (meta_data_size + pixel_data_size == 0)
+ continue;
+
+ /* Pixel data */
+ if (pixel_data_size > 0)
+ {
+ if (!write_card32 (cache, image_data_offset + 8))
+ return FALSE;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (meta_data_size > 0)
+ {
+ if (!write_card32 (cache, image_data_offset + pixel_data_size + 8))
+ return FALSE;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (pixel_data_size > 0)
+ {
+ if (!write_pixdata (cache, &image->pixdata))
+ return FALSE;
+ }
+
+ if (meta_data_size > 0)
+ {
+ int ofs = image_data_offset + pixel_data_size + 20;
+
+ if (image->has_embedded_rect)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+
+ ofs += 8;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (image->n_attach_points > 0)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+
+ ofs += 4 + 4 * image->n_attach_points;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (image->n_display_names > 0)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (image->has_embedded_rect)
+ {
+ if (!write_card16 (cache, image->x0) ||
+ !write_card16 (cache, image->y0) ||
+ !write_card16 (cache, image->x1) ||
+ !write_card16 (cache, image->y1))
+ return FALSE;
+ }
+
+ if (image->n_attach_points > 0)
+ {
+ if (!write_card32 (cache, image->n_attach_points))
+ return FALSE;
+
+ for (j = 0; j < 2 * image->n_attach_points; j++)
+ {
+ if (!write_card16 (cache, image->attach_points[j]))
+ return FALSE;
+ }
+ }
+
+ if (image->n_display_names > 0)
+ {
+ if (!write_card32 (cache, image->n_display_names))
+ return FALSE;
+
+ ofs += 4 + 8 * image->n_display_names;
+
+ for (j = 0; j < 2 * image->n_display_names; j++)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+
+ ofs += ALIGN_VALUE (strlen (image->display_names[j]) + 1, 4);
+ }
+
+ for (j = 0; j < 2 * image->n_display_names; j++)
+ {
+ if (!write_string (cache, image->display_names[j]))
+ return FALSE;
+ }
+ }
+ }
+
+ image_data_offset += pixel_data_size + meta_data_size + 8;
+ }
+
*offset = next_offset;
node = node->next;
}
@@ -643,6 +1031,7 @@ main (int argc, char **argv)
if (!force_update && is_cache_up_to_date (path))
return 0;
+ g_type_init ();
build_cache (path);
return 0;