From 3fc42d7ab9602fc8f9e41c09de427f2e76950286 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 15 Mar 2005 13:18:25 +0000 Subject: [PATCH] Update spec. 2005-03-15 Anders Carlsson * 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. --- ChangeLog | 23 +++ ChangeLog.pre-2-10 | 23 +++ ChangeLog.pre-2-8 | 23 +++ docs/iconcache.txt | 70 +++++-- gtk/gtkiconcache.c | 169 ++++++++++++++++- gtk/gtkiconcache.h | 19 ++ gtk/gtkicontheme.c | 31 ++-- gtk/updateiconcache.c | 417 ++++++++++++++++++++++++++++++++++++++++-- 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 + + * 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 * 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 + + * 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 * 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 + + * 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 * 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 +#include #ifdef HAVE_MMAP #include @@ -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 +#include 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 #include +#include 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_single_node_size (HashNode *node) +get_image_pixel_data_size (Image *image) +{ + if (image->has_pixdata) + return image->pixdata.length + 8; + + return 0; +} + +guint +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;