gtk+ r19726 - in trunk: . docs/reference/gtk/tmpl gtk tests



Author: johan
Date: Fri Mar  7 00:08:16 2008
New Revision: 19726
URL: http://svn.gnome.org/viewvc/gtk+?rev=19726&view=rev

Log:
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



Modified:
   trunk/ChangeLog
   trunk/docs/reference/gtk/tmpl/gtkiconfactory.sgml
   trunk/gtk/gtkbuilder.c
   trunk/gtk/gtkbuilderprivate.h
   trunk/gtk/gtkiconfactory.c
   trunk/tests/buildertest.c

Modified: trunk/docs/reference/gtk/tmpl/gtkiconfactory.sgml
==============================================================================
--- trunk/docs/reference/gtk/tmpl/gtkiconfactory.sgml	(original)
+++ trunk/docs/reference/gtk/tmpl/gtkiconfactory.sgml	Fri Mar  7 00:08:16 2008
@@ -35,6 +35,77 @@
 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>
 

Modified: trunk/gtk/gtkbuilder.c
==============================================================================
--- trunk/gtk/gtkbuilder.c	(original)
+++ trunk/gtk/gtkbuilder.c	Fri Mar  7 00:08:16 2008
@@ -1234,18 +1234,7 @@
               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 @@
   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"

Modified: trunk/gtk/gtkbuilderprivate.h
==============================================================================
--- trunk/gtk/gtkbuilderprivate.h	(original)
+++ trunk/gtk/gtkbuilderprivate.h	Fri Mar  7 00:08:16 2008
@@ -125,5 +125,7 @@
 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__ */

Modified: trunk/gtk/gtkiconfactory.c
==============================================================================
--- trunk/gtk/gtkiconfactory.c	(original)
+++ trunk/gtk/gtkiconfactory.c	Fri Mar  7 00:08:16 2008
@@ -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 @@
 };
 
 
+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 @@
    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)
@@ -114,6 +132,13 @@
 }
 
 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)
 {
   g_free (key);
@@ -2700,6 +2725,204 @@
   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 */

Modified: trunk/tests/buildertest.c
==============================================================================
--- trunk/tests/buildertest.c	(original)
+++ trunk/tests/buildertest.c	Fri Mar  7 00:08:16 2008
@@ -1793,6 +1793,34 @@
   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 @@
   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();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]