[gtk+/wip/resources: 1/3] Add resource support for GtkBuilder



commit 29b868cdc230822d6b46d1f5df515ea9fae3ca03
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Jan 12 18:11:19 2012 +0100

    Add resource support for GtkBuilder
    
    There are new calls to load ui files from resources, and
    you can now read pixbufs by using relative paths in a ui
    file read from a resource, or by using absolute resource:/// uris.

 gtk/gtkbuilder.c        |  193 ++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkbuilder.h        |    7 ++
 gtk/gtkbuilderprivate.h |    2 +
 3 files changed, 199 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 273285f..f4904fa 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -296,6 +296,7 @@ struct _GtkBuilderPrivate
   GSList *delayed_properties;
   GSList *signals;
   gchar *filename;
+  gchar *resource_prefix;
 };
 
 G_DEFINE_TYPE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
@@ -356,6 +357,7 @@ gtk_builder_finalize (GObject *object)
   
   g_free (priv->domain);
   g_free (priv->filename);
+  g_free (priv->resource_prefix);
   
   g_hash_table_destroy (priv->objects);
 
@@ -913,7 +915,9 @@ gtk_builder_add_from_file (GtkBuilder   *builder,
     }
   
   g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
   builder->priv->filename = g_strdup (filename);
+  builder->priv->resource_prefix = NULL;
 
   _gtk_builder_parser_parse_buffer (builder, filename,
                                     buffer, length,
@@ -980,7 +984,9 @@ gtk_builder_add_objects_from_file (GtkBuilder   *builder,
     }
   
   g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
   builder->priv->filename = g_strdup (filename);
+  builder->priv->resource_prefix = NULL;
 
   _gtk_builder_parser_parse_buffer (builder, filename,
                                     buffer, length,
@@ -999,6 +1005,157 @@ gtk_builder_add_objects_from_file (GtkBuilder   *builder,
 }
 
 /**
+ * gtk_builder_add_from_resource:
+ * @builder: a #GtkBuilder
+ * @resource_path: the path of the resource file to parse
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Parses a resource file containing a <link linkend="BUILDER-UI">GtkBuilder
+ * UI definition</link> and merges it with the current contents of @builder.
+ *
+ * Upon errors 0 will be returned and @error will be assigned a
+ * #GError from the #GTK_BUILDER_ERROR, #G_MARKUP_ERROR or #G_RESOURCE_ERROR
+ * domain.
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: 3.4
+ **/
+guint
+gtk_builder_add_from_resource (GtkBuilder   *builder,
+			       const gchar  *resource_path,
+			       GError      **error)
+{
+  GError *tmp_error;
+  GBytes *data;
+  char *filename_for_errors;
+  char *slash;
+
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (resource_path != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+  tmp_error = NULL;
+
+  data = g_resources_lookup_data (resource_path, 0, &tmp_error);
+  if (data == NULL)
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+
+  g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
+  builder->priv->filename = g_strdup (".");
+
+  slash = strrchr (resource_path, '/');
+  if (slash != NULL)
+    builder->priv->resource_prefix =
+      g_strndup (resource_path, slash - resource_path + 1);
+  else
+    builder->priv->resource_prefix =
+      g_strdup ("/");
+
+  filename_for_errors = g_strconcat ("<resource>", resource_path, NULL);
+
+  _gtk_builder_parser_parse_buffer (builder, filename_for_errors,
+                                    g_bytes_get_data (data, NULL), g_bytes_get_size (data),
+                                    NULL,
+                                    &tmp_error);
+
+  g_free (filename_for_errors);
+  g_bytes_unref (data);
+
+  if (tmp_error != NULL)
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+
+  return 1;
+}
+
+/**
+ * gtk_builder_add_objects_from_resource:
+ * @builder: a #GtkBuilder
+ * @resource_path: the path of the resource file to parse
+ * @object_ids: (array zero-terminated=1) (element-type utf8): nul-terminated array of objects to build
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Parses a resource file containing a <link linkend="BUILDER-UI">GtkBuilder
+ * UI definition</link> building only the requested objects and merges
+ * them with the current contents of @builder.
+ *
+ * Upon errors 0 will be returned and @error will be assigned a
+ * #GError from the #GTK_BUILDER_ERROR, #G_MARKUP_ERROR or #G_RESOURCE_ERROR
+ * domain.
+ *
+ * <note><para>
+ * If you are adding an object that depends on an object that is not
+ * its child (for instance a #GtkTreeView that depends on its
+ * #GtkTreeModel), you have to explicitely list all of them in @object_ids.
+ * </para></note>
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: 3.4
+ **/
+guint
+gtk_builder_add_objects_from_resource (GtkBuilder   *builder,
+				       const gchar  *resource_path,
+				       gchar       **object_ids,
+				       GError      **error)
+{
+  GError *tmp_error;
+  GBytes *data;
+  char *filename_for_errors;
+  char *slash;
+
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (resource_path != NULL, 0);
+  g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+  tmp_error = NULL;
+
+  data = g_resources_lookup_data (resource_path, 0, &tmp_error);
+  if (data == NULL)
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+
+  g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
+  builder->priv->filename = g_strdup (".");
+
+  slash = strrchr (resource_path, '/');
+  if (slash != NULL)
+    builder->priv->resource_prefix =
+      g_strndup (resource_path, slash - resource_path + 1);
+  else
+    builder->priv->resource_prefix =
+      g_strdup ("/");
+
+  filename_for_errors = g_strconcat ("<resource>", resource_path, NULL);
+
+  _gtk_builder_parser_parse_buffer (builder, filename_for_errors,
+                                    g_bytes_get_data (data, NULL), g_bytes_get_size (data),
+                                    object_ids,
+                                    &tmp_error);
+  g_free (filename_for_errors);
+  g_bytes_unref (data);
+
+  if (tmp_error != NULL)
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+
+  return 1;
+}
+
+/**
  * gtk_builder_add_from_string:
  * @builder: a #GtkBuilder
  * @buffer: the string to parse
@@ -1030,7 +1187,9 @@ gtk_builder_add_from_string (GtkBuilder   *builder,
   tmp_error = NULL;
 
   g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
   builder->priv->filename = g_strdup (".");
+  builder->priv->resource_prefix = NULL;
 
   _gtk_builder_parser_parse_buffer (builder, "<input>",
                                     buffer, length,
@@ -1087,7 +1246,9 @@ gtk_builder_add_objects_from_string (GtkBuilder   *builder,
   tmp_error = NULL;
 
   g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
   builder->priv->filename = g_strdup (".");
+  builder->priv->resource_prefix = NULL;
 
   _gtk_builder_parser_parse_buffer (builder, "<input>",
                                     buffer, length,
@@ -1655,7 +1816,7 @@ gtk_builder_value_from_string_type (GtkBuilder   *builder,
         {
           gchar *filename;
           GError *tmp_error = NULL;
-          GdkPixbuf *pixbuf;
+          GdkPixbuf *pixbuf = NULL;
        
           if (gtk_builder_get_object (builder, string))
             {
@@ -1668,8 +1829,21 @@ gtk_builder_value_from_string_type (GtkBuilder   *builder,
               return FALSE;
             }
 
-	  filename = _gtk_builder_get_absolute_filename (builder, string);
-          pixbuf = gdk_pixbuf_new_from_file (filename, &tmp_error);
+	  filename = _gtk_builder_get_resource_path (builder, string);
+	  if (filename != NULL)
+	    {
+	      GInputStream *stream = g_resources_open_stream (filename, 0, &tmp_error);
+	      if (stream != NULL)
+		{
+		  pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &tmp_error);
+		  g_object_unref (stream);
+		}
+	    }
+	  else
+	    {
+	      filename = _gtk_builder_get_absolute_filename (builder, string);
+	      pixbuf = gdk_pixbuf_new_from_file (filename, &tmp_error);
+	    }
 
           if (pixbuf == NULL)
             {
@@ -1899,6 +2073,19 @@ gtk_builder_error_quark (void)
 }
 
 gchar *
+_gtk_builder_get_resource_path (GtkBuilder *builder, const gchar *string)
+{
+  if (g_str_has_prefix (string, "resource:///"))
+    return g_uri_unescape_string (string + 11, "/");
+
+  if (g_path_is_absolute (string) ||
+      builder->priv->resource_prefix == NULL)
+    return NULL;
+
+  return g_build_path ("/", builder->priv->resource_prefix, string, NULL);
+}
+
+gchar *
 _gtk_builder_get_absolute_filename (GtkBuilder *builder, const gchar *string)
 {
   gchar *filename;
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index cdbd06f..0059e12 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -119,6 +119,9 @@ GtkBuilder*  gtk_builder_new                     (void);
 guint        gtk_builder_add_from_file           (GtkBuilder    *builder,
                                                   const gchar   *filename,
                                                   GError       **error);
+guint        gtk_builder_add_from_resource       (GtkBuilder    *builder,
+                                                  const gchar   *resource_path,
+                                                  GError       **error);
 guint        gtk_builder_add_from_string         (GtkBuilder    *builder,
                                                   const gchar   *buffer,
                                                   gsize          length,
@@ -127,6 +130,10 @@ guint        gtk_builder_add_objects_from_file   (GtkBuilder    *builder,
                                                   const gchar   *filename,
                                                   gchar        **object_ids,
                                                   GError       **error);
+guint        gtk_builder_add_objects_from_resource(GtkBuilder    *builder,
+                                                  const gchar   *resource_path,
+                                                  gchar        **object_ids,
+                                                  GError       **error);
 guint        gtk_builder_add_objects_from_string (GtkBuilder    *builder,
                                                   const gchar   *buffer,
                                                   gsize          length,
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index f58da23..e7528bc 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -149,6 +149,8 @@ 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_resource_path (GtkBuilder *builder,
+					  const gchar *string);
 gchar *   _gtk_builder_get_absolute_filename (GtkBuilder *builder,
 					      const gchar *string);
 



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