Implement GtkBuildable on GtkIconFactory, to make it possible to register

2008-03-06  Johan Dahlin  <jdahlin@async.com.br>

    * docs/reference/gtk/tmpl/gtkiconfactory.sgml:
    * gtk/gtkbuilder.c:
    * gtk/gtkbuilderprivate.h:
    * gtk/gtkiconfactory.c:
    * tests/buildertest.c:
    Implement GtkBuildable on GtkIconFactory, to make
    it possible to register custom stock icons.
    Fixes #517066


svn path=/trunk/; revision=19726
This commit is contained in:
Johan Dahlin 2008-03-07 00:08:16 +00:00 committed by Johan Dahlin
parent 6f9bcaa8b7
commit 61be2a7127
6 changed files with 360 additions and 14 deletions

View File

@ -1,3 +1,14 @@
2008-03-06 Johan Dahlin <jdahlin@async.com.br>
* docs/reference/gtk/tmpl/gtkiconfactory.sgml:
* gtk/gtkbuilder.c:
* gtk/gtkbuilderprivate.h:
* gtk/gtkiconfactory.c:
* tests/buildertest.c:
Implement GtkBuildable on GtkIconFactory, to make
it possible to register custom stock icons.
Fixes #517066
2008-03-06 Johan Dahlin <johan@gnome.org>
Make gtk-doc happy:

View File

@ -35,6 +35,77 @@ gtk_widget_render_icon(). These functions take the theme into account when
looking up the icon to use for a given stock ID.
</para>
<refsect2 id="GtkIconFactory-BUILDER-UI"><title>GtkIconFactory as GtkBuildable</title>
<para>
GtkIconFactory supports a custom &lt;sources&gt; element, which
can contain multiple &lt;source&gt; elements.
The following attributes are allowed:
<variablelist>
<varlistentry>
<term>stock-id</term>
<listitem><para>The stock id of the source, a string.
This attribute is mandatory</para></listitem>
</varlistentry>
<varlistentry>
<term>filename</term>
<listitem><para>The filename of the source, a string.
This attribute is mandatory</para>
</listitem>
</varlistentry>
<varlistentry>
<term>icon-name</term>
<listitem><para>The icon name for the source, a string.
This attribute is optional.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>size</term>
<listitem><para>Size of the icon, a #GtkIconSize enum value.
This attribute is optional.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>direction</term>
<listitem><para>Direction of the source, a #GtkTextDirection enum value.
This attribute is optional.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>state</term>
<listitem><para>State of the source, a #GtkStateType enum value.
This attribute is optional.</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<example>
<title>A <structname>GtkIconFactory</structname> UI definition fragment.</title>
<programlisting><![CDATA[
<object class="GtkIconFactory" id="iconfactory1">
<sources>
<source stock-id="apple-red" filename="apple-red.png"/>
</sources>
</object>
<object class="GtkWindow" id="window1">
<child>
<object class="GtkButton" id="apple_button">
<property name="label">apple-red</property>
<property name="use-stock">True</property>
</object>
</child>
</object>
]]></programlisting>
</example>
</refsect2>
<!-- ##### SECTION See_Also ##### -->
<para>

View File

@ -1234,18 +1234,7 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
return FALSE;
}
if (g_path_is_absolute (string))
filename = g_strdup (string);
else
{
gchar *dirname;
dirname = g_path_get_dirname (builder->priv->filename);
filename = g_build_filename (dirname, string, NULL);
g_free (dirname);
}
filename = _gtk_builder_get_absolute_filename (builder, string);
pixbuf = gdk_pixbuf_new_from_file (filename, &tmp_error);
if (pixbuf == NULL)
@ -1466,6 +1455,26 @@ gtk_builder_error_quark (void)
return g_quark_from_static_string ("gtk-builder-error-quark");
}
gchar *
_gtk_builder_get_absolute_filename (GtkBuilder *builder, const gchar *string)
{
gchar *filename;
gchar *dirname = NULL;
if (g_path_is_absolute (string))
return g_strdup (string);
if (builder->priv->filename &&
strcmp (builder->priv->filename, ".") != 0)
dirname = g_path_get_dirname (builder->priv->filename);
else
dirname = g_get_current_dir ();
filename = g_build_filename (dirname, string, NULL);
g_free (dirname);
return filename;
}
#define __GTK_BUILDER_C__
#include "gtkaliasdef.c"

View File

@ -125,5 +125,7 @@ gboolean _gtk_builder_flags_from_string (GType type,
gchar * _gtk_builder_parser_translate (const gchar *domain,
const gchar *context,
const gchar *text);
gchar * _gtk_builder_get_absolute_filename (GtkBuilder *builder,
const gchar *string);
#endif /* __GTK_BUILDER_PRIVATE_H__ */

View File

@ -1,6 +1,6 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2000 Red Hat, Inc.
*
* 2008 Johan Dahlin
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@ -37,6 +37,8 @@
#include "gtkstock.h"
#include "gtkwidget.h"
#include "gtkintl.h"
#include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
#include "gtkalias.h"
@ -83,6 +85,20 @@ struct _GtkIconSource
};
static void
gtk_icon_factory_buildable_init (GtkBuildableIface *iface);
static gboolean gtk_icon_factory_buildable_custom_tag_start (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *tagname,
GMarkupParser *parser,
gpointer *data);
static void gtk_icon_factory_buildable_custom_tag_end (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *tagname,
gpointer *user_data);
static void gtk_icon_factory_finalize (GObject *object);
static void get_default_icons (GtkIconFactory *icon_factory);
static void icon_source_clear (GtkIconSource *source);
@ -96,7 +112,9 @@ static GtkIconSize icon_size_register_intern (const gchar *name,
0, 0, 0, \
any_direction, any_state, any_size }
G_DEFINE_TYPE (GtkIconFactory, gtk_icon_factory, G_TYPE_OBJECT)
G_DEFINE_TYPE_WITH_CODE (GtkIconFactory, gtk_icon_factory, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_icon_factory_buildable_init))
static void
gtk_icon_factory_init (GtkIconFactory *factory)
@ -113,6 +131,13 @@ gtk_icon_factory_class_init (GtkIconFactoryClass *klass)
object_class->finalize = gtk_icon_factory_finalize;
}
static void
gtk_icon_factory_buildable_init (GtkBuildableIface *iface)
{
iface->custom_tag_start = gtk_icon_factory_buildable_custom_tag_start;
iface->custom_tag_end = gtk_icon_factory_buildable_custom_tag_end;
}
static void
free_icon_set (gpointer key, gpointer value, gpointer data)
{
@ -2700,6 +2725,204 @@ _gtk_icon_factory_list_ids (void)
return ids;
}
typedef struct {
GSList *sources;
gboolean in_source;
} IconFactoryParserData;
typedef struct {
gchar *stock_id;
gchar *filename;
gchar *icon_name;
GtkTextDirection direction;
GtkIconSize size;
GtkStateType state;
} IconSourceParserData;
static void
icon_source_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **names,
const gchar **values,
gpointer user_data,
GError **error)
{
gint i;
gchar *stock_id = NULL;
gchar *filename = NULL;
gchar *icon_name = NULL;
GtkIconSize size = -1;
GtkTextDirection direction = -1;
GtkStateType state = -1;
IconFactoryParserData *parser_data;
IconSourceParserData *source_data;
parser_data = (IconFactoryParserData*)user_data;
if (!parser_data->in_source)
{
if (strcmp (element_name, "sources") != 0)
{
g_warning ("Unexpected element %s, expected <sources>", element_name);
return;
}
parser_data->in_source = TRUE;
return;
}
else
{
if (strcmp (element_name, "source") != 0)
{
g_warning ("Unexpected element %s, expected <source>", element_name);
return;
}
}
for (i = 0; names[i]; i++)
{
if (strcmp (names[i], "stock-id") == 0)
stock_id = g_strdup (values[i]);
else if (strcmp (names[i], "filename") == 0)
filename = g_strdup (values[i]);
else if (strcmp (names[i], "icon-name") == 0)
icon_name = g_strdup (values[i]);
else if (strcmp (names[i], "size") == 0)
{
if (!_gtk_builder_flags_from_string (GTK_TYPE_ICON_SIZE,
values[i],
&size,
error))
return;
}
else if (strcmp (names[i], "direction") == 0)
{
if (!_gtk_builder_flags_from_string (GTK_TYPE_TEXT_DIRECTION,
values[i],
&direction,
error))
return;
}
else if (strcmp (names[i], "state") == 0)
{
if (!_gtk_builder_flags_from_string (GTK_TYPE_STATE_TYPE,
values[i],
&state,
error))
return;
}
}
if (!stock_id || !filename)
{
g_warning ("<source> requires a stock_id and a filename");
return;
}
source_data = g_slice_new (IconSourceParserData);
source_data->stock_id = stock_id;
source_data->filename = filename;
source_data->icon_name = icon_name;
source_data->size = size;
source_data->direction = direction;
source_data->state = state;
parser_data->sources = g_slist_prepend (parser_data->sources, source_data);
}
static const GMarkupParser icon_source_parser =
{
icon_source_start_element,
};
static gboolean
gtk_icon_factory_buildable_custom_tag_start (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *tagname,
GMarkupParser *parser,
gpointer *data)
{
g_assert (buildable);
if (strcmp (tagname, "sources") == 0)
{
IconFactoryParserData *parser_data;
parser_data = g_slice_new0 (IconFactoryParserData);
*parser = icon_source_parser;
*data = parser_data;
return TRUE;
}
return FALSE;
}
static void
gtk_icon_factory_buildable_custom_tag_end (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *tagname,
gpointer *user_data)
{
GtkIconFactory *icon_factory;
icon_factory = GTK_ICON_FACTORY (buildable);
if (strcmp (tagname, "sources") == 0)
{
IconFactoryParserData *parser_data;
GtkIconSource *icon_source;
GtkIconSet *icon_set;
GSList *l;
parser_data = (IconFactoryParserData*)user_data;
for (l = parser_data->sources; l; l = l->next)
{
IconSourceParserData *source_data = l->data;
icon_set = gtk_icon_factory_lookup (icon_factory, source_data->stock_id);
if (!icon_set)
{
icon_set = gtk_icon_set_new ();
gtk_icon_factory_add (icon_factory, source_data->stock_id, icon_set);
}
icon_source = gtk_icon_source_new ();
if (source_data->filename)
{
gchar *filename;
filename = _gtk_builder_get_absolute_filename (builder, source_data->filename);
gtk_icon_source_set_filename (icon_source, filename);
g_free (filename);
}
if (source_data->icon_name)
gtk_icon_source_set_icon_name (icon_source, source_data->icon_name);
if (source_data->size != -1)
gtk_icon_source_set_size (icon_source, source_data->size);
if (source_data->direction != -1)
gtk_icon_source_set_direction (icon_source, source_data->direction);
if (source_data->state != -1)
gtk_icon_source_set_state (icon_source, source_data->state);
/* Inline source_add() to avoid creating a copy */
g_assert (source->type != GTK_ICON_SOURCE_EMPTY);
icon_set->sources = g_slist_insert_sorted (icon_set->sources,
icon_source,
icon_source_compare);
gtk_icon_set_unref (icon_set);
g_free (source_data->stock_id);
g_free (source_data->filename);
g_free (source_data->icon_name);
g_slice_free (IconSourceParserData, source_data);
}
g_slist_free (parser_data->sources);
g_slice_free (IconFactoryParserData, parser_data);
}
}
#ifdef G_OS_WIN32
/* DLL ABI stability backward compatibility versions */

View File

@ -1793,6 +1793,34 @@ test_reference_counting (void)
g_object_unref (builder);
}
static void
test_icon_factory (void)
{
GtkBuilder *builder;
const gchar buffer1[] =
"<interface>"
" <object class=\"GtkIconFactory\" id=\"iconfactory1\">"
" <sources>"
" <source stock-id=\"apple-red\" filename=\"apple-red.png\"/>"
" </sources>"
" </object>"
"</interface>";
GObject *factory;
GtkIconSet *icon_set;
GtkWidget *image;
builder = builder_new_from_string (buffer1, -1, NULL);
factory = gtk_builder_get_object (builder, "iconfactory1");
g_assert (factory != NULL);
icon_set = gtk_icon_factory_lookup (GTK_ICON_FACTORY (factory), "apple-red");
g_assert (icon_set != NULL);
gtk_icon_factory_add_default (GTK_ICON_FACTORY (factory));
image = gtk_image_new_from_stock ("apple-red", GTK_ICON_SIZE_BUTTON);
g_assert (image != NULL);
}
static void
test_file (const gchar *filename)
{
@ -1874,5 +1902,7 @@ main (int argc, char **argv)
g_test_add_func ("/Builder/Value From String", test_value_from_string);
g_test_add_func ("/Builder/Reference Counting", test_reference_counting);
g_test_add_func ("/Builder/Window", test_window);
g_test_add_func ("/Builder/IconFactory", test_icon_factory);
return g_test_run();
}