Commit 4255e436 authored by Martin Nordholts's avatar Martin Nordholts

Bug 555954 – Merge Tagging of Gimp Resources GSoC Project

Merge the rest of the tagging code developed on the tagging branch
by Aurimas Juška. Development will now continue in trunk.

* app/core/gimptag.[ch]: New files (not strictly true but almost)
implementing the represention of a tag.

* app/core/gimptagcache.[ch]: New files implementing functionality
for loading and saving tags to tags.xml, and assigning loaded tags
to tagged objects.

* app/core/gimpfilteredcontainer.[ch]: New files implementing a
tag filtered GimpContainer.

* app/widgets/gimptagentry.[ch]: New files implementing a
GtkEntry-like widget for entering tags.

* app/widgets/gimpcombotagentry.[ch]: New files implementing a
combobox-like widget for selecting tags.

* app/widgets/gimptagpopup.[ch]: New files implementing a popup of
all available tags that can be selected and combined in a
checkbox-like way.

* app/core/gimp.[ch]: Add a GimpTagCache member and manage tag
assignment and saving and loading to/from tags.xml.

* app/widgets/gimpdatafactoryview.c: Add the tag query and tag
assignment widgets to the UI and show the tag filtered items
instead of all items.

* app/core/Makefile.am
* app/widgets/Makefile.am: Add new files.

* app/core/core-types.h
* app/widgets/widgets-types.h: Add new types.

svn path=/trunk/; revision=27816
parent 9c912cf0
2008-12-20 Martin Nordholts <martinn@svn.gnome.org>
Bug 555954 Merge Tagging of Gimp Resources GSoC Project
Merge the rest of the tagging code developed on the tagging branch
by Aurimas Juška. Development will now continue in trunk.
* app/core/gimptag.[ch]: New files (not strictly true but almost)
implementing the represention of a tag.
* app/core/gimptagcache.[ch]: New files implementing functionality
for loading and saving tags to tags.xml, and assigning loaded tags
to tagged objects.
* app/core/gimpfilteredcontainer.[ch]: New files implementing a
tag filtered GimpContainer.
* app/widgets/gimptagentry.[ch]: New files implementing a
GtkEntry-like widget for entering tags.
* app/widgets/gimpcombotagentry.[ch]: New files implementing a
combobox-like widget for selecting tags.
* app/widgets/gimptagpopup.[ch]: New files implementing a popup of
all available tags that can be selected and combined in a
checkbox-like way.
* app/core/gimp.[ch]: Add a GimpTagCache member and manage tag
assignment and saving and loading to/from tags.xml.
* app/widgets/gimpdatafactoryview.c: Add the tag query and tag
assignment widgets to the UI and show the tag filtered items
instead of all items.
* app/core/Makefile.am
* app/widgets/Makefile.am: Add new files.
* app/core/core-types.h
* app/widgets/widgets-types.h: Add new types.
2008-12-20 Martin Nordholts <martinn@svn.gnome.org>
Bug 555954 Merge Tagging of Gimp Resources GSoC Project
......
......@@ -168,6 +168,8 @@ libappcore_a_sources = \
gimperror.h \
gimpfilloptions.c \
gimpfilloptions.h \
gimpfilteredcontainer.c \
gimpfilteredcontainer.h \
gimpfloatingselundo.c \
gimpfloatingselundo.h \
gimpgradient.c \
......@@ -325,6 +327,8 @@ libappcore_a_sources = \
gimpsubprogress.h \
gimptag.c \
gimptag.h \
gimptagcache.c \
gimptagcache.h \
gimptagged.c \
gimptagged.h \
gimptemplate.c \
......
......@@ -67,12 +67,13 @@ typedef struct _GimpImage GimpImage;
/* containers */
typedef struct _GimpContainer GimpContainer;
typedef struct _GimpDocumentList GimpDocumentList;
typedef struct _GimpDrawableStack GimpDrawableStack;
typedef struct _GimpItemStack GimpItemStack;
typedef struct _GimpList GimpList;
typedef struct _GimpToolPresets GimpToolPresets;
typedef struct _GimpContainer GimpContainer;
typedef struct _GimpDocumentList GimpDocumentList;
typedef struct _GimpDrawableStack GimpDrawableStack;
typedef struct _GimpFilteredContainer GimpFilteredContainer;
typedef struct _GimpItemStack GimpItemStack;
typedef struct _GimpList GimpList;
typedef struct _GimpToolPresets GimpToolPresets;
/* context objects */
......@@ -102,6 +103,7 @@ typedef struct _GimpGradient GimpGradient;
typedef struct _GimpPalette GimpPalette;
typedef struct _GimpPattern GimpPattern;
typedef struct _GimpPatternClipboard GimpPatternClipboard;
typedef struct _GimpTagCache GimpTagCache;
/* drawable objects */
......
......@@ -58,6 +58,7 @@
#include "gimpbuffer.h"
#include "gimpcontext.h"
#include "gimpdatafactory.h"
#include "gimptagcache.h"
#include "gimpdocumentlist.h"
#include "gimpgradient-load.h"
#include "gimpgradient.h"
......@@ -242,6 +243,8 @@ gimp_init (Gimp *gimp)
gimp->gradient_factory = NULL;
gimp->palette_factory = NULL;
gimp->tag_cache = NULL;
gimp->pdb = gimp_pdb_new (gimp);
xcf_init (gimp);
......@@ -355,6 +358,12 @@ gimp_finalize (GObject *object)
gimp->palette_factory = NULL;
}
if (gimp->tag_cache)
{
g_object_unref (gimp->tag_cache);
gimp->tag_cache = NULL;
}
if (gimp->fonts)
{
g_object_unref (gimp->fonts);
......@@ -477,6 +486,9 @@ gimp_get_memsize (GimpObject *object,
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimp->palette_factory),
gui_size);
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimp->tag_cache),
gui_size);
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimp->pdb), gui_size);
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimp->tool_info_list),
......@@ -588,6 +600,8 @@ gimp_real_initialize (Gimp *gimp,
gimp_object_set_static_name (GIMP_OBJECT (gimp->palette_factory),
"palette factory");
gimp->tag_cache = gimp_tag_cache_new ();
gimp_paint_init (gimp);
/* Set the last values used to default values. */
......@@ -649,6 +663,8 @@ gimp_real_exit (Gimp *gimp,
gimp_plug_in_manager_exit (gimp->plug_in_manager);
gimp_modules_unload (gimp);
gimp_tag_cache_save (gimp->tag_cache);
gimp_data_factory_data_save (gimp->brush_factory);
gimp_data_factory_data_save (gimp->pattern_factory);
gimp_data_factory_data_save (gimp->gradient_factory);
......@@ -865,6 +881,18 @@ gimp_restore (Gimp *gimp,
status_callback (NULL, _("Modules"), 0.7);
gimp_modules_load (gimp);
/* update tag cache */
status_callback (NULL, _("Updating tag cache"), 0.8);
gimp_tag_cache_load (gimp->tag_cache);
gimp_tag_cache_add_container (gimp->tag_cache,
gimp_data_factory_get_container (gimp->brush_factory));
gimp_tag_cache_add_container (gimp->tag_cache,
gimp_data_factory_get_container (gimp->pattern_factory));
gimp_tag_cache_add_container (gimp->tag_cache,
gimp_data_factory_get_container (gimp->gradient_factory));
gimp_tag_cache_add_container (gimp->tag_cache,
gimp_data_factory_get_container (gimp->palette_factory));
g_signal_emit (gimp, gimp_signals[RESTORE], 0, status_callback);
}
......
......@@ -95,6 +95,8 @@ struct _Gimp
GimpDataFactory *gradient_factory;
GimpDataFactory *palette_factory;
GimpTagCache *tag_cache;
GimpPDB *pdb;
GimpContainer *tool_info_list;
......
This diff is collapsed.
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* gimpfilteredcontainer.h
* Copyright (C) 2008 Aurimas Juška <aurisj@svn.gnome.org>
*
* 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.
*/
#ifndef __GIMP_FILTERED_CONTAINER_H__
#define __GIMP_FILTERED_CONTAINER_H__
#include "gimplist.h"
#define GIMP_TYPE_FILTERED_CONTAINER (gimp_filtered_container_get_type ())
#define GIMP_FILTERED_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_FILTERED_CONTAINER, GimpFilteredContainer))
#define GIMP_FILTERED_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_FILTERED_CONTAINER, GimpFilteredContainerClass))
#define GIMP_IS_FILTERED_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_FILTERED_CONTAINER))
#define GIMP_FILTERED_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_FILTERED_CONTAINER, GimpFilteredContainerClass))
typedef struct _GimpFilteredContainerClass GimpFilteredContainerClass;
struct _GimpFilteredContainer
{
GimpList parent_instance;
GimpContainer *src_container;
GList *filter;
GHashTable *tag_ref_counts;
gint tag_count;
};
struct _GimpFilteredContainerClass
{
GimpContainerClass parent_class;
void (* tag_count_changed) (GimpFilteredContainer *container,
gint count);
};
GType gimp_filtered_container_get_type (void) G_GNUC_CONST;
GimpContainer * gimp_filtered_container_new (GimpContainer *src_container,
GCompareFunc sort_func);
void gimp_filtered_container_set_filter (GimpFilteredContainer *filtered_container,
GList *tags);
const GList * gimp_filtered_container_get_filter (GimpFilteredContainer *filtered_container);
gint gimp_filtered_container_get_tag_count (GimpFilteredContainer *container);
#endif /* __GIMP_FILTERED_CONTAINER_H__ */
......@@ -22,12 +22,16 @@
#include "config.h"
#include <glib-object.h>
#include <string.h>
#include "core-types.h"
#include "gimptag.h"
#define GIMP_TAG_INTERNAL_PREFIX "gimp:"
G_DEFINE_TYPE (GimpTag, gimp_tag, G_TYPE_OBJECT)
#define parent_class gimp_tag_parent_class
......@@ -41,6 +45,133 @@ gimp_tag_class_init (GimpTagClass *klass)
static void
gimp_tag_init (GimpTag *tag)
{
tag->tag = 0;
tag->collate_key = 0;
}
/**
* gimp_tag_new:
* @tag_string: a tag name.
*
* If given tag name is not valid, an attempt will be made to fix it.
*
* Return value: a new #GimpTag object, or NULL if tag string is invalid and
* cannot be fixed.
**/
GimpTag *
gimp_tag_new (const char *tag_string)
{
GimpTag *tag;
gchar *tag_name;
gchar *case_folded;
gchar *collate_key;
g_return_val_if_fail (tag_string != NULL, NULL);
tag_name = gimp_tag_string_make_valid (tag_string);
if (! tag_name)
{
return NULL;
}
tag = g_object_new (GIMP_TYPE_TAG, NULL);
tag->tag = g_quark_from_string (tag_name);
case_folded = g_utf8_casefold (tag_name, -1);
collate_key = g_utf8_collate_key (case_folded, -1);
tag->collate_key = g_quark_from_string (collate_key);
g_free (collate_key);
g_free (case_folded);
g_free (tag_name);
return tag;
}
/**
* gimp_tag_try_new:
* @tag_string: a tag name.
*
* Similar to gimp_tag_new(), but returns NULL if tag is surely not equal
* to any of currently created tags. It is useful for tag querying to avoid
* unneeded comparisons. If tag is created, however, it does not mean that
* it would necessarily match with some other tag.
*
* Return value: new #GimpTag object, or NULL if tag will not match with any
* other #GimpTag.
**/
GimpTag *
gimp_tag_try_new (const char *tag_string)
{
GimpTag *tag;
gchar *tag_name;
gchar *case_folded;
gchar *collate_key;
GQuark tag_quark;
GQuark collate_key_quark;
tag_name = gimp_tag_string_make_valid (tag_string);
if (! tag_name)
{
return NULL;
}
case_folded = g_utf8_casefold (tag_name, -1);
collate_key = g_utf8_collate_key (case_folded, -1);
collate_key_quark = g_quark_try_string (collate_key);
g_free (collate_key);
g_free (case_folded);
if (! collate_key_quark)
{
g_free (tag_name);
return NULL;
}
tag_quark = g_quark_from_string (tag_name);
g_free (tag_name);
if (! tag_quark)
{
return NULL;
}
tag = g_object_new (GIMP_TYPE_TAG, NULL);
tag->tag = tag_quark;
tag->collate_key = collate_key_quark;
return tag;
}
/**
* gimp_tag_get_name:
* @tag: a gimp tag.
*
* Retrieve name of the tag.
*
* Return value: name of tag.
**/
const gchar *
gimp_tag_get_name (GimpTag *tag)
{
g_return_val_if_fail (GIMP_IS_TAG (tag), NULL);
return g_quark_to_string (tag->tag);
}
/**
* gimp_tag_get_hash:
* @tag: a gimp tag.
*
* Hashing function which is useful, for example, to store #GimpTag in
* a #GHashTable.
*
* Return value: hash value for tag.
**/
guint
gimp_tag_get_hash (GimpTag *tag)
{
g_return_val_if_fail (GIMP_IS_TAG (tag), -1);
return tag->collate_key;
}
/**
......@@ -59,5 +190,156 @@ gimp_tag_equals (const GimpTag *tag,
g_return_val_if_fail (GIMP_IS_TAG (tag), FALSE);
g_return_val_if_fail (GIMP_IS_TAG (other), FALSE);
return FALSE;
return tag->collate_key == other->collate_key;
}
/**
* gimp_tag_compare_func:
* @p1: pointer to left-hand #GimpTag object.
* @p2: pointer to right-hand #GimpTag object.
*
* Compares tags according to tag comparison rules. Useful for sorting
* functions.
*
* Return value: meaning of return value is the same as in strcmp().
**/
int
gimp_tag_compare_func (const void *p1,
const void *p2)
{
GimpTag *t1 = GIMP_TAG (p1);
GimpTag *t2 = GIMP_TAG (p2);
return g_strcmp0 (g_quark_to_string (t1->collate_key),
g_quark_to_string (t2->collate_key));
}
/**
* gimp_tag_compare_with_string:
* @tag: a #GimpTag object.
* @tag_string: pointer to right-hand #GimpTag object.
*
* Compares tag and a string according to tag comparison rules. Similar to
* gimp_tag_compare_func(), but can be used without creating temporary tag
* object.
*
* Return value: meaning of return value is the same as in strcmp().
**/
gint
gimp_tag_compare_with_string (GimpTag *tag,
const char *tag_string)
{
gchar *case_folded;
const gchar *collate_key;
gchar *collate_key2;
gint result;
g_return_val_if_fail (GIMP_IS_TAG (tag), 0);
g_return_val_if_fail (tag_string != NULL, 0);
collate_key = g_quark_to_string (tag->collate_key);
case_folded = g_utf8_casefold (tag_string, -1);
collate_key2 = g_utf8_collate_key (case_folded, -1);
result = g_strcmp0 (collate_key, collate_key2);
g_free (collate_key2);
g_free (case_folded);
return result;
}
/**
* gimp_tag_string_make_valid:
* @tag_string: a text string.
*
* Tries to create a valid tag string from given @tag_string.
*
* Return value: a newly allocated tag string in case given @tag_string was
* valid or could be fixed, otherwise NULL. Allocated value should be freed
* using g_free().
**/
gchar *
gimp_tag_string_make_valid (const gchar *tag_string)
{
gchar *tag;
GString *buffer;
gchar *tag_cursor;
gunichar c;
g_return_val_if_fail (tag_string, NULL);
tag = g_utf8_normalize (tag_string, -1, G_NORMALIZE_ALL);
if (! tag)
{
return NULL;
}
tag = g_strstrip (tag);
if (! *tag)
{
g_free (tag);
return NULL;
}
buffer = g_string_new ("");
tag_cursor = tag;
if (g_str_has_prefix (tag_cursor, GIMP_TAG_INTERNAL_PREFIX))
{
tag_cursor += strlen (GIMP_TAG_INTERNAL_PREFIX);
}
do
{
c = g_utf8_get_char (tag_cursor);
tag_cursor = g_utf8_next_char (tag_cursor);
if (g_unichar_isprint (c)
&& ! gimp_tag_is_tag_separator (c))
{
g_string_append_unichar (buffer, c);
}
} while (c);
g_free (tag);
tag = g_string_free (buffer, FALSE);
tag = g_strstrip (tag);
if (! *tag)
{
g_free (tag);
return NULL;
}
return tag;
}
/**
* gimp_tag_is_tag_separator:
* @c: Unicode character.
*
* Defines a set of characters that are considered tag separators. The
* tag separators are hand-picked from the set of characters with the
* Terminal_Punctuation property as specified in the version 5.1.0 of
* the Unicode Standard.
*
* Return value: %TRUE if the character is a tag separator.
*/
gboolean
gimp_tag_is_tag_separator (gunichar c)
{
switch (c)
{
case 0x002C: /* COMMA */
case 0x060C: /* ARABIC COMMA */
case 0x07F8: /* NKO COMMA */
case 0x1363: /* ETHIOPIC COMMA */
case 0x1802: /* MONGOLIAN COMMA */
case 0x1808: /* MONGOLIAN MANCHU COMMA */
case 0x3001: /* IDEOGRAPHIC COMMA */
case 0xA60D: /* VAI COMMA */
case 0xFE50: /* SMALL COMMA */
case 0xFF0C: /* FULLWIDTH COMMA */
case 0xFF64: /* HALFWIDTH IDEOGRAPHIC COMMA */
return TRUE;
default:
return FALSE;
}
}
......@@ -39,6 +39,9 @@ typedef struct _GimpTagClass GimpTagClass;
struct _GimpTag
{
GObject parent_instance;
GQuark tag;
GQuark collate_key;
};
struct _GimpTagClass
......@@ -46,12 +49,21 @@ struct _GimpTagClass
GObjectClass parent_class;
};
GType gimp_tag_get_type (void) G_GNUC_CONST;
GType gimp_tag_get_type (void) G_GNUC_CONST;
GimpTag * gimp_tag_new (const gchar *tag_string);
GimpTag * gimp_tag_try_new (const gchar *tag_string);
gboolean gimp_tag_equals (const GimpTag *tag,
const GimpTag *other);
const gchar * gimp_tag_get_name (GimpTag *tag);
guint gimp_tag_get_hash (GimpTag *tag);
gboolean gimp_tag_equals (const GimpTag *tag,
const GimpTag *other);
gint gimp_tag_compare_func (const void *p1,
const void *p2);
gint gimp_tag_compare_with_string (GimpTag *tag,
const gchar *tag_string);
gchar * gimp_tag_string_make_valid (const gchar *tag_string);
gboolean gimp_tag_is_tag_separator (gunichar c);
#endif /* __GIMP_TAG_H__ */
This diff is collapsed.
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimptagcache.h
* Copyright (C) 2008 Aurimas Juška <aurisj@svn.gnome.org>
*
* 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.
*/
#ifndef __GIMP_TAG_CACHE_H__
#define __GIMP_TAG_CACHE_H__
#include "gimpobject.h"
#define GIMP_TYPE_TAG_CACHE (gimp_tag_cache_get_type ())
#define GIMP_TAG_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TAG_CACHE, GimpTagCache))
#define GIMP_TAG_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TAG_CACHE, GimpTagCacheClass))
#define GIMP_IS_TAG_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TAG_CACHE))
#define GIMP_IS_TAG_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TAG_CACHE))
#define GIMP_TAG_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TAG_CACHE, GimpTagCacheClass))
typedef struct _GimpTagCacheClass GimpTagCacheClass;
typedef struct _GimpTagCachePriv GimpTagCachePriv;
struct _GimpTagCache
{
GimpObject parent_instance;
GimpTagCachePriv *priv;
};
struct _GimpTagCacheClass
{
GimpObjectClass parent_class;
};
GType gimp_tag_cache_get_type (void) G_GNUC_CONST;
GimpTagCache * gimp_tag_cache_new (void);
void gimp_tag_cache_save (GimpTagCache *cache);
void gimp_tag_cache_load (GimpTagCache *cache);
void gimp_tag_cache_add_container (GimpTagCache *cache,
GimpContainer *container);
#endif /* __GIMP_TAG_CACHE_H__ */
......@@ -65,6 +65,8 @@ libappwidgets_a_sources = \
gimpcolorpanel.h \
gimpcolorselectorpalette.c \
gimpcolorselectorpalette.h \
gimpcombotagentry.c \
gimpcombotagentry.h \
gimpcomponenteditor.c \
gimpcomponenteditor.h \
gimpcontainerbox.c \
......@@ -265,6 +267,10 @@ libappwidgets_a_sources = \
gimpstringaction.h \
gimpstrokeeditor.c \
gimpstrokeeditor.h \
gimptagentry.c \
gimptagentry.h \
gimptagpopup.c \
gimptagpopup.h \
gimptemplateeditor.c \
gimptemplateeditor.h \
gimptemplateview.c \
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpcombotagentry.c
* Copyright (C) 2008 Aurimas Juška <aurisj@svn.gnome.org>
*
* 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.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "widgets-types.h"
#include "core/gimpcontainer.h"
#include "core/gimpfilteredcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpviewable.h"
#include "core/gimptag.h"
#include "core/gimptagged.h"
#include "gimptagentry.h"
#include "gimptagpopup.h"
#include "gimpcombotagentry.h"
static GObject* gimp_combo_tag_entry_constructor (GType type,
guint n_params,
GObjectConstructParam *params);
static void gimp_combo_tag_entry_dispose (GObject *object);
static gboolean gimp_combo_tag_entry_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer user_data);
static gboolean gimp_combo_tag_entry_event (GtkWidget *widget,
GdkEvent *event,
gpointer user_data);
static void gimp_combo_tag_entry_style_set (GtkWidget *widget,
GtkStyle *previous_style);
static void gimp_combo_tag_entry_popup_list (GimpComboTagEntry *combo_entry);
static void gimp_combo_tag_entry_popup_destroy (GtkObject *object,
GimpComboTagEntry *combo_entry);
static void gimp_combo_tag_entry_tag_count_changed (GimpFilteredContainer *container,
gint tag_count,
GimpComboTagEntry *combo_entry);
static void gimp_combo_tag_entry_get_arrow_rect (GimpComboTagEntry *combo_entry,
GdkRectangle *arrow_rect);
G_DEFINE_TYPE (GimpComboTagEntry, gimp_combo_tag_entry, GIMP_TYPE_TAG_ENTRY);
#define parent_class gimp_combo_tag_entry_parent_class
static void
gimp_combo_tag_entry_class_init (GimpComboTagEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class