Compare commits
19 Commits
tree-list-
...
composite-
Author | SHA1 | Date | |
---|---|---|---|
|
1cffd1de56 | ||
|
6b141bff77 | ||
|
13870e733c | ||
|
e0ce659f34 | ||
|
dc78589ce2 | ||
|
e6007f10ac | ||
|
2b422848a3 | ||
|
b39ae75a0e | ||
|
828338fbf8 | ||
|
329335132c | ||
|
7d53df8ccb | ||
|
bfdf7571b1 | ||
|
976b14cb63 | ||
|
af394406f7 | ||
|
a6685346f1 | ||
|
0f257f1892 | ||
|
04444664a4 | ||
|
a3b93112bb | ||
|
4d2bf8ef4a |
@@ -536,6 +536,7 @@ gtk_builder_add_objects_from_string
|
||||
gtk_builder_add_objects_from_resource
|
||||
gtk_builder_get_object
|
||||
gtk_builder_get_objects
|
||||
gtk_builder_expose_object
|
||||
gtk_builder_connect_signals
|
||||
gtk_builder_connect_signals_full
|
||||
gtk_builder_set_translation_domain
|
||||
|
@@ -1130,7 +1130,8 @@ gtktypebuiltins.c: @REBUILD@ $(gtk_public_h_sources) $(deprecated_h_sources) gtk
|
||||
gtkresources.h: gtk.gresource.xml
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/gtk.gresource.xml \
|
||||
--target=$@ --sourcedir=$(srcdir) --c-name _gtk --generate-header --manual-register
|
||||
gtkresources.c: gtk.gresource.xml gtk-default.css gtk-win32.css gtk-win32-xp.css gtk-win32-base.css gtk-win32-classic.css $(DND_CURSORS)
|
||||
gtkresources.c: gtk.gresource.xml \
|
||||
$(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies gtk.gresource.xml)
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/gtk.gresource.xml \
|
||||
--target=$@ --sourcedir=$(srcdir) --c-name _gtk --generate-source --manual-register
|
||||
|
||||
|
405
gtk/gtkbuilder.c
405
gtk/gtkbuilder.c
@@ -123,22 +123,24 @@
|
||||
* (can be specified by their name, nick or integer value), flags (can be
|
||||
* specified by their name, nick, integer value, optionally combined with "|",
|
||||
* e.g. "GTK_VISIBLE|GTK_REALIZED") and colors (in a format understood by
|
||||
* gdk_color_parse()). Objects can be referred to by their name. Pixbufs can be
|
||||
* specified as a filename of an image file to load. In general, GtkBuilder
|
||||
* allows forward references to objects — an object doesn't have to be
|
||||
* constructed before it can be referred to. The exception to this rule is that
|
||||
* an object has to be constructed before it can be used as the value of a
|
||||
* construct-only property.
|
||||
* gdk_color_parse()). Pixbufs can be specified as a filename of an image file to load.
|
||||
* Objects can be referred to by their name and by default refer to objects declared
|
||||
* in the local xml fragment and objects exposed via gtk_builder_expose_object().
|
||||
*
|
||||
* In general, GtkBuilder allows forward references to objects &mdash declared
|
||||
* in the local xml; an object doesn't have to be constructed before it can be referred to.
|
||||
* The exception to this rule is that an object has to be constructed before
|
||||
* it can be used as the value of a construct-only property.
|
||||
*
|
||||
* Signal handlers are set up with the <signal> element. The "name"
|
||||
* attribute specifies the name of the signal, and the "handler" attribute
|
||||
* specifies the function to connect to the signal. By default, GTK+ tries to
|
||||
* find the handler using g_module_symbol(), but this can be changed by passing
|
||||
* a custom #GtkBuilderConnectFunc to gtk_builder_connect_signals_full(). The
|
||||
* remaining attributes, "after", "swapped" and "object", have the same meaning
|
||||
* attributes "after", "swapped" and "object", have the same meaning
|
||||
* as the corresponding parameters of the g_signal_connect_object() or
|
||||
* g_signal_connect_data() functions. A "last_modification_time" attribute
|
||||
* is also allowed, but it does not have a meaning to the builder.
|
||||
* g_signal_connect_data() functions. A "last_modification_time" attribute is also
|
||||
* allowed, but it does not have a meaning to the builder.
|
||||
*
|
||||
* Sometimes it is necessary to refer to widgets which have implicitly been
|
||||
* constructed by GTK+ as part of a composite widget, to set properties on them
|
||||
@@ -272,6 +274,8 @@ struct _GtkBuilderPrivate
|
||||
GSList *signals;
|
||||
gchar *filename;
|
||||
gchar *resource_prefix;
|
||||
|
||||
GType ignore_type;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
|
||||
@@ -490,22 +494,24 @@ gtk_builder_get_parameters (GtkBuilder *builder,
|
||||
if (G_IS_PARAM_SPEC_OBJECT (pspec) &&
|
||||
(G_PARAM_SPEC_VALUE_TYPE (pspec) != GDK_TYPE_PIXBUF))
|
||||
{
|
||||
GObject *object = gtk_builder_get_object (builder, prop->data);
|
||||
GObject *object;
|
||||
|
||||
if (object)
|
||||
if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
|
||||
{
|
||||
g_value_init (¶meter.value, G_OBJECT_TYPE (object));
|
||||
g_value_set_object (¶meter.value, object);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
|
||||
object = gtk_builder_get_object (builder, prop->data);
|
||||
|
||||
if (!object)
|
||||
{
|
||||
g_warning ("Failed to get constuct only property "
|
||||
"%s of %s with value `%s'",
|
||||
prop->name, object_name, prop->data);
|
||||
continue;
|
||||
}
|
||||
g_value_init (¶meter.value, G_OBJECT_TYPE (object));
|
||||
g_value_set_object (¶meter.value, object);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delay setting property */
|
||||
property = g_slice_new (DelayedProperty);
|
||||
property->object = g_strdup (object_name);
|
||||
@@ -562,7 +568,7 @@ gtk_builder_get_internal_child (GtkBuilder *builder,
|
||||
obj = gtk_buildable_get_internal_child (GTK_BUILDABLE (info->object),
|
||||
builder,
|
||||
childname);
|
||||
};
|
||||
}
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
@@ -574,6 +580,33 @@ gtk_builder_get_internal_child (GtkBuilder *builder,
|
||||
return obj;
|
||||
}
|
||||
|
||||
static inline void
|
||||
object_set_name (GObject *object, const gchar *name)
|
||||
{
|
||||
if (GTK_IS_BUILDABLE (object))
|
||||
gtk_buildable_set_name (GTK_BUILDABLE (object), name);
|
||||
else
|
||||
g_object_set_data_full (object, "gtk-builder-name", g_strdup (name), g_free);
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_builder_add_object (GtkBuilder *builder,
|
||||
const gchar *id,
|
||||
GObject *object)
|
||||
{
|
||||
object_set_name (object, id);
|
||||
g_hash_table_insert (builder->priv->objects, g_strdup (id), g_object_ref (object));
|
||||
}
|
||||
|
||||
const gchar *
|
||||
_gtk_builder_object_get_name (GObject *object)
|
||||
{
|
||||
if (GTK_IS_BUILDABLE (object))
|
||||
return gtk_buildable_get_name (GTK_BUILDABLE (object));
|
||||
else
|
||||
return g_object_get_data (object, "gtk-builder-name");
|
||||
}
|
||||
|
||||
GObject *
|
||||
_gtk_builder_construct (GtkBuilder *builder,
|
||||
ObjectInfo *info,
|
||||
@@ -587,25 +620,32 @@ _gtk_builder_construct (GtkBuilder *builder,
|
||||
gboolean custom_set_property;
|
||||
GtkBuildable *buildable;
|
||||
|
||||
g_assert (info->class_name != NULL);
|
||||
object_type = gtk_builder_get_type_from_name (builder, info->class_name);
|
||||
if (object_type == G_TYPE_INVALID)
|
||||
if ((object_type = info->object_type) == G_TYPE_INVALID)
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_INVALID_VALUE,
|
||||
"Invalid object type `%s'",
|
||||
info->class_name);
|
||||
g_type_name (object_type));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_builder_get_parameters (builder, object_type,
|
||||
/* Safeguard to avoid recursion if we are building a new type with builder */
|
||||
if (object_type == builder->priv->ignore_type)
|
||||
return NULL;
|
||||
|
||||
gtk_builder_get_parameters (builder, info->object_type,
|
||||
info->id,
|
||||
info->properties,
|
||||
¶meters,
|
||||
&construct_parameters);
|
||||
|
||||
if (info->constructor)
|
||||
if (info->object)
|
||||
{
|
||||
/* external_object */
|
||||
obj = g_object_ref (info->object);
|
||||
}
|
||||
else if (info->constructor)
|
||||
{
|
||||
GObject *constructor;
|
||||
|
||||
@@ -662,7 +702,7 @@ _gtk_builder_construct (GtkBuilder *builder,
|
||||
g_object_ref_sink (obj);
|
||||
|
||||
GTK_NOTE (BUILDER,
|
||||
g_print ("created %s of type %s\n", info->id, info->class_name));
|
||||
g_print ("created %s of type %s\n", info->id, g_type_name (object_type)));
|
||||
|
||||
for (i = 0; i < construct_parameters->len; i++)
|
||||
{
|
||||
@@ -703,29 +743,16 @@ _gtk_builder_construct (GtkBuilder *builder,
|
||||
g_value_unset (¶m->value);
|
||||
}
|
||||
g_array_free (parameters, TRUE);
|
||||
|
||||
if (GTK_IS_BUILDABLE (obj))
|
||||
gtk_buildable_set_name (buildable, info->id);
|
||||
else
|
||||
g_object_set_data_full (obj,
|
||||
"gtk-builder-name",
|
||||
g_strdup (info->id),
|
||||
g_free);
|
||||
|
||||
/* we already own a reference to obj. put it in the hash table. */
|
||||
g_hash_table_insert (builder->priv->objects, g_strdup (info->id), obj);
|
||||
/* put it in the hash table. */
|
||||
_gtk_builder_add_object (builder, info->id, obj);
|
||||
|
||||
/* we already own a reference to obj. */
|
||||
g_object_unref (obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_builder_add_object (GtkBuilder *builder,
|
||||
const gchar *id,
|
||||
GObject *object)
|
||||
{
|
||||
g_hash_table_insert (builder->priv->objects, g_strdup (id), g_object_ref (object));
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_builder_add (GtkBuilder *builder,
|
||||
ChildInfo *child_info)
|
||||
@@ -851,6 +878,41 @@ gtk_builder_new (void)
|
||||
return g_object_new (GTK_TYPE_BUILDER, NULL);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_builder_add_from_file_real (GtkBuilder *builder,
|
||||
const gchar *filename,
|
||||
gchar **object_ids,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error = NULL;
|
||||
gchar *buffer;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
object_ids, &tmp_error);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_builder_add_from_file:
|
||||
* @builder: a #GtkBuilder
|
||||
@@ -873,41 +935,11 @@ gtk_builder_add_from_file (GtkBuilder *builder,
|
||||
const gchar *filename,
|
||||
GError **error)
|
||||
{
|
||||
gchar *buffer;
|
||||
gsize length;
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (filename != NULL, 0);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, 0);
|
||||
|
||||
tmp_error = NULL;
|
||||
|
||||
if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
NULL,
|
||||
&tmp_error);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return gtk_builder_add_from_file_real (builder, filename, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -941,34 +973,52 @@ gtk_builder_add_objects_from_file (GtkBuilder *builder,
|
||||
gchar **object_ids,
|
||||
GError **error)
|
||||
{
|
||||
gchar *buffer;
|
||||
gsize length;
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (filename != 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);
|
||||
|
||||
return gtk_builder_add_from_file_real (builder, filename, object_ids, error);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_builder_add_from_resource_real (GtkBuilder *builder,
|
||||
const gchar *path,
|
||||
gchar **object_ids,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error;
|
||||
GBytes *data;
|
||||
char *filename_for_errors;
|
||||
char *slash;
|
||||
|
||||
tmp_error = NULL;
|
||||
|
||||
if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
|
||||
data = g_resources_lookup_data (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 (filename);
|
||||
builder->priv->resource_prefix = NULL;
|
||||
builder->priv->filename = g_strdup (".");
|
||||
|
||||
_gtk_builder_parser_parse_buffer (builder, filename,
|
||||
buffer, length,
|
||||
object_ids,
|
||||
&tmp_error);
|
||||
slash = strrchr (path, '/');
|
||||
if (slash != NULL)
|
||||
builder->priv->resource_prefix = g_strndup (path, slash - path + 1);
|
||||
else
|
||||
builder->priv->resource_prefix = g_strdup ("/");
|
||||
|
||||
g_free (buffer);
|
||||
filename_for_errors = g_strconcat ("<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)
|
||||
{
|
||||
@@ -1001,53 +1051,11 @@ 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;
|
||||
return gtk_builder_add_from_resource_real (builder, resource_path, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1081,46 +1089,31 @@ gtk_builder_add_objects_from_resource (GtkBuilder *builder,
|
||||
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;
|
||||
return gtk_builder_add_from_resource_real (builder, resource_path,
|
||||
object_ids, error);
|
||||
}
|
||||
|
||||
data = g_resources_lookup_data (resource_path, 0, &tmp_error);
|
||||
if (data == NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
static guint
|
||||
gtk_builder_add_from_string_real (GtkBuilder *builder,
|
||||
const gchar *buffer,
|
||||
gsize length,
|
||||
gchar **object_ids,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
g_free (builder->priv->filename);
|
||||
g_free (builder->priv->resource_prefix);
|
||||
builder->priv->filename = g_strdup (".");
|
||||
builder->priv->resource_prefix = NULL;
|
||||
|
||||
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);
|
||||
|
||||
_gtk_builder_parser_parse_buffer (builder, "<input>", buffer, length,
|
||||
object_ids, &tmp_error);
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
@@ -1153,30 +1146,11 @@ gtk_builder_add_from_string (GtkBuilder *builder,
|
||||
gsize length,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (buffer != NULL, 0);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, 0);
|
||||
|
||||
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,
|
||||
NULL,
|
||||
&tmp_error);
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
return gtk_builder_add_from_string_real (builder, buffer, length, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1211,32 +1185,13 @@ gtk_builder_add_objects_from_string (GtkBuilder *builder,
|
||||
gchar **object_ids,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (buffer != 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;
|
||||
|
||||
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,
|
||||
object_ids,
|
||||
&tmp_error);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return gtk_builder_add_from_string_real (builder, buffer, length,
|
||||
object_ids, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1340,6 +1295,39 @@ gtk_builder_get_translation_domain (GtkBuilder *builder)
|
||||
return builder->priv->domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_builder_expose_object:
|
||||
* @builder: a #GtkBuilder
|
||||
* @name: the name of the object exposed to the builder
|
||||
* @object: the object to expose
|
||||
*
|
||||
* Add @object to the @builder object pool so it can be referenced just like any
|
||||
* other object built by builder.
|
||||
*
|
||||
* To make this function even more useful a new special entry point element
|
||||
* <external-object> is defined. It is similar to <object> but has
|
||||
* to reference an external object exposed with this function.
|
||||
* This way you can change properties and even add children to an
|
||||
* external object using builder, not just reference it.
|
||||
*
|
||||
* Since: 3.8
|
||||
**/
|
||||
void
|
||||
gtk_builder_expose_object (GtkBuilder *builder,
|
||||
const gchar *name,
|
||||
GObject *object)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_BUILDER (builder));
|
||||
g_return_if_fail (name && name[0]);
|
||||
g_return_if_fail (gtk_builder_get_object (builder, name) == NULL);
|
||||
|
||||
object_set_name (object, name);
|
||||
g_hash_table_insert (builder->priv->objects,
|
||||
g_strdup (name),
|
||||
g_object_ref (object));
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
GModule *module;
|
||||
gpointer data;
|
||||
@@ -1480,7 +1468,8 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
|
||||
if (signal->connect_object_name)
|
||||
{
|
||||
connect_object = g_hash_table_lookup (builder->priv->objects,
|
||||
signal->connect_object_name);
|
||||
signal->connect_object_name);
|
||||
|
||||
if (!connect_object)
|
||||
g_warning ("Could not lookup object %s on signal %s of object %s",
|
||||
signal->connect_object_name, signal->name,
|
||||
@@ -2088,3 +2077,15 @@ _gtk_builder_get_absolute_filename (GtkBuilder *builder, const gchar *string)
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_builder_set_ignore_type (GtkBuilder *builder, GType ignore_type)
|
||||
{
|
||||
builder->priv->ignore_type = ignore_type;
|
||||
}
|
||||
|
||||
GType
|
||||
_gtk_builder_get_ignore_type (GtkBuilder *builder)
|
||||
{
|
||||
return builder->priv->ignore_type;
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ typedef struct _GtkBuilderPrivate GtkBuilderPrivate;
|
||||
* @GTK_BUILDER_ERROR_VERSION_MISMATCH: The input file requires a newer version
|
||||
* of GTK+.
|
||||
* @GTK_BUILDER_ERROR_DUPLICATE_ID: An object id occurred twice.
|
||||
* @GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH: The Class template is designed for a different class.
|
||||
*
|
||||
* Error codes that identify various errors that can occur while using
|
||||
* #GtkBuilder.
|
||||
@@ -73,7 +74,8 @@ typedef enum
|
||||
GTK_BUILDER_ERROR_MISSING_PROPERTY_VALUE,
|
||||
GTK_BUILDER_ERROR_INVALID_VALUE,
|
||||
GTK_BUILDER_ERROR_VERSION_MISMATCH,
|
||||
GTK_BUILDER_ERROR_DUPLICATE_ID
|
||||
GTK_BUILDER_ERROR_DUPLICATE_ID,
|
||||
GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH
|
||||
} GtkBuilderError;
|
||||
|
||||
GQuark gtk_builder_error_quark (void);
|
||||
@@ -141,6 +143,9 @@ guint gtk_builder_add_objects_from_string (GtkBuilder *builder,
|
||||
GObject* gtk_builder_get_object (GtkBuilder *builder,
|
||||
const gchar *name);
|
||||
GSList* gtk_builder_get_objects (GtkBuilder *builder);
|
||||
void gtk_builder_expose_object (GtkBuilder *builder,
|
||||
const gchar *name,
|
||||
GObject *object);
|
||||
void gtk_builder_connect_signals (GtkBuilder *builder,
|
||||
gpointer user_data);
|
||||
void gtk_builder_connect_signals_full (GtkBuilder *builder,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
start = element interface {
|
||||
attribute domain { text } ?,
|
||||
( requires | object | menu ) *
|
||||
( requires | object | external-object | template | menu ) *
|
||||
}
|
||||
|
||||
requires = element requires {
|
||||
@@ -16,9 +16,23 @@ object = element object {
|
||||
(property | signal | child | ANY) *
|
||||
}
|
||||
|
||||
object = element external-object {
|
||||
attribute id { xsd:ID },
|
||||
attribute class { text },
|
||||
(property | signal | child | ANY) *
|
||||
}
|
||||
|
||||
object = element template {
|
||||
attribute id { xsd:ID },
|
||||
attribute class { text },
|
||||
attribute parent { text },
|
||||
(property | signal | child | ANY) *
|
||||
}
|
||||
|
||||
property = element property {
|
||||
attribute name { text },
|
||||
attribute translatable { "yes" | "no" } ?,
|
||||
attribute external-object { "yes" | "no" } ?,
|
||||
attribute comments { text } ?,
|
||||
attribute context { text } ?,
|
||||
text ?
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include "gtkversion.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
#include "gtkcontainer.h"
|
||||
|
||||
static void free_property_info (PropertyInfo *info);
|
||||
static void free_object_info (ObjectInfo *info);
|
||||
@@ -64,6 +64,32 @@ state_pop (ParserData *data)
|
||||
#define state_peek_info(data, st) ((st*)state_peek(data))
|
||||
#define state_pop_info(data, st) ((st*)state_pop(data))
|
||||
|
||||
static void
|
||||
error_generic (GError **error,
|
||||
GtkBuilderError code,
|
||||
ParserData *data,
|
||||
const gchar *tag,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
gint line_number, char_number;
|
||||
gchar *message;
|
||||
va_list args;
|
||||
|
||||
g_markup_parse_context_get_position (data->ctx,
|
||||
&line_number,
|
||||
&char_number);
|
||||
|
||||
va_start (args, format);
|
||||
message = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
g_set_error (error, GTK_BUILDER_ERROR, code, "%s:%d:%d <%s> %s",
|
||||
data->filename, line_number, char_number, tag, message);
|
||||
|
||||
g_free (message);
|
||||
}
|
||||
|
||||
static void
|
||||
error_missing_attribute (ParserData *data,
|
||||
const gchar *tag,
|
||||
@@ -190,6 +216,13 @@ builder_construct (ParserData *data,
|
||||
if (object_info->object)
|
||||
return object_info->object;
|
||||
|
||||
/* Safeguard to avoid recursion if we are building a new type with builder
|
||||
* _gtk_builder_construct() also checks for this, but there is no need to
|
||||
* reverse the property list if we are not going to build the object.
|
||||
*/
|
||||
if (object_info->object_type == _gtk_builder_get_ignore_type (data->builder))
|
||||
return NULL;
|
||||
|
||||
object_info->properties = g_slist_reverse (object_info->properties);
|
||||
|
||||
object = _gtk_builder_construct (data->builder, object_info, error);
|
||||
@@ -203,24 +236,19 @@ builder_construct (ParserData *data,
|
||||
return object;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
static GType
|
||||
_get_type_by_symbol (const gchar* symbol)
|
||||
{
|
||||
static GModule *module = NULL;
|
||||
GTypeGetFunc func;
|
||||
GType type;
|
||||
|
||||
if (!module)
|
||||
module = g_module_open (NULL, 0);
|
||||
|
||||
if (!g_module_symbol (module, symbol, (gpointer)&func))
|
||||
return NULL;
|
||||
return G_TYPE_INVALID;
|
||||
|
||||
type = func ();
|
||||
if (type == G_TYPE_INVALID)
|
||||
return NULL;
|
||||
|
||||
return g_strdup (g_type_name (type));
|
||||
return func ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -295,6 +323,29 @@ is_requested_object (const gchar *object,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parser_add_object_id (ParserData *data,
|
||||
const gchar *object_id,
|
||||
GError **error)
|
||||
{
|
||||
gint line, line2;
|
||||
|
||||
g_markup_parse_context_get_position (data->ctx, &line, NULL);
|
||||
line2 = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_id));
|
||||
if (line2 != 0)
|
||||
{
|
||||
g_set_error (error, GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_DUPLICATE_ID,
|
||||
_("Duplicate object ID '%s' on line %d (previously on line %d)"),
|
||||
object_id, line, line2);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_object (GMarkupParseContext *context,
|
||||
ParserData *data,
|
||||
@@ -303,13 +354,13 @@ parse_object (GMarkupParseContext *context,
|
||||
const gchar **values,
|
||||
GError **error)
|
||||
{
|
||||
GType object_type = G_TYPE_INVALID;
|
||||
ObjectInfo *object_info;
|
||||
ChildInfo* child_info;
|
||||
int i;
|
||||
gchar *object_class = NULL;
|
||||
gchar *object_id = NULL;
|
||||
gchar *constructor = NULL;
|
||||
gint line, line2;
|
||||
ChildInfo *child_info;
|
||||
const gchar *object_class = NULL;
|
||||
const gchar *object_id = NULL;
|
||||
const gchar *constructor = NULL;
|
||||
gint i, line;
|
||||
|
||||
child_info = state_peek_info (data, ChildInfo);
|
||||
if (child_info && strcmp (child_info->tag.name, "object") == 0)
|
||||
@@ -321,19 +372,19 @@ parse_object (GMarkupParseContext *context,
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (names[i], "class") == 0)
|
||||
object_class = g_strdup (values[i]);
|
||||
object_class = values[i];
|
||||
else if (strcmp (names[i], "id") == 0)
|
||||
object_id = g_strdup (values[i]);
|
||||
object_id = values[i];
|
||||
else if (strcmp (names[i], "constructor") == 0)
|
||||
constructor = g_strdup (values[i]);
|
||||
constructor = values[i];
|
||||
else if (strcmp (names[i], "type-func") == 0)
|
||||
{
|
||||
/* Call the GType function, and return the name of the GType,
|
||||
* it's guaranteed afterwards that g_type_from_name on the name
|
||||
* will return our GType
|
||||
*/
|
||||
object_class = _get_type_by_symbol (values[i]);
|
||||
if (!object_class)
|
||||
object_type = _get_type_by_symbol (values[i]);
|
||||
if (object_type == G_TYPE_INVALID)
|
||||
{
|
||||
g_markup_parse_context_get_position (context, &line, NULL);
|
||||
g_set_error (error, GTK_BUILDER_ERROR,
|
||||
@@ -350,7 +401,7 @@ parse_object (GMarkupParseContext *context,
|
||||
}
|
||||
}
|
||||
|
||||
if (!object_class)
|
||||
if (object_type == G_TYPE_INVALID && !object_class)
|
||||
{
|
||||
error_missing_attribute (data, element_name, "class", error);
|
||||
return;
|
||||
@@ -362,6 +413,20 @@ parse_object (GMarkupParseContext *context,
|
||||
return;
|
||||
}
|
||||
|
||||
if (object_type == G_TYPE_INVALID)
|
||||
{
|
||||
/* Make sure the class is initialized so we have intern string available */
|
||||
object_type = gtk_builder_get_type_from_name (data->builder, object_class);
|
||||
|
||||
if (object_type == G_TYPE_INVALID)
|
||||
{
|
||||
g_set_error (error, GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_INVALID_VALUE,
|
||||
_("Invalid class: '%s'"), object_class);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
++data->cur_object_level;
|
||||
|
||||
/* check if we reached a requested object (if it is specified) */
|
||||
@@ -379,36 +444,24 @@ parse_object (GMarkupParseContext *context,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (object_class);
|
||||
g_free (object_id);
|
||||
g_free (constructor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ((data->in_external_object && !data->external_object) ||
|
||||
data->template_level)
|
||||
return;
|
||||
|
||||
object_info = g_slice_new0 (ObjectInfo);
|
||||
object_info->class_name = object_class;
|
||||
object_info->id = object_id;
|
||||
object_info->constructor = constructor;
|
||||
object_info->object_type = object_type;
|
||||
object_info->id = g_strdup (object_id);
|
||||
object_info->constructor = g_strdup (constructor);
|
||||
state_push (data, object_info);
|
||||
object_info->tag.name = element_name;
|
||||
|
||||
if (child_info)
|
||||
object_info->parent = (CommonInfo*)child_info;
|
||||
|
||||
g_markup_parse_context_get_position (context, &line, NULL);
|
||||
line2 = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_id));
|
||||
if (line2 != 0)
|
||||
{
|
||||
g_set_error (error, GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_DUPLICATE_ID,
|
||||
_("Duplicate object ID '%s' on line %d (previously on line %d)"),
|
||||
object_id, line, line2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line));
|
||||
parser_add_object_id (data, object_id, error);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -420,7 +473,6 @@ free_object_info (ObjectInfo *info)
|
||||
(GFunc)free_property_info, NULL);
|
||||
g_slist_free (info->properties);
|
||||
g_free (info->constructor);
|
||||
g_free (info->class_name);
|
||||
g_free (info->id);
|
||||
g_slice_free (ObjectInfo, info);
|
||||
}
|
||||
@@ -531,20 +583,21 @@ parse_property (ParserData *data,
|
||||
}
|
||||
|
||||
info = g_slice_new0 (PropertyInfo);
|
||||
info->name = name;
|
||||
info->name = g_intern_string (name);
|
||||
info->translatable = translatable;
|
||||
info->context = context;
|
||||
info->text = g_string_new ("");
|
||||
info->context = context;
|
||||
info->text = g_string_new ("");
|
||||
state_push (data, info);
|
||||
|
||||
info->tag.name = element_name;
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static void
|
||||
free_property_info (PropertyInfo *info)
|
||||
{
|
||||
g_free (info->data);
|
||||
g_free (info->name);
|
||||
g_slice_free (PropertyInfo, info);
|
||||
}
|
||||
|
||||
@@ -556,7 +609,7 @@ parse_signal (ParserData *data,
|
||||
GError **error)
|
||||
{
|
||||
SignalInfo *info;
|
||||
gchar *name = NULL;
|
||||
const gchar *name = NULL;
|
||||
gchar *handler = NULL;
|
||||
gchar *object = NULL;
|
||||
gboolean after = FALSE;
|
||||
@@ -575,7 +628,7 @@ parse_signal (ParserData *data,
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (names[i], "name") == 0)
|
||||
name = g_strdup (values[i]);
|
||||
name = values[i];
|
||||
else if (strcmp (names[i], "handler") == 0)
|
||||
handler = g_strdup (values[i]);
|
||||
else if (strcmp (names[i], "after") == 0)
|
||||
@@ -617,7 +670,7 @@ parse_signal (ParserData *data,
|
||||
swapped = TRUE;
|
||||
|
||||
info = g_slice_new0 (SignalInfo);
|
||||
info->name = name;
|
||||
info->name = g_intern_string (name);
|
||||
info->handler = handler;
|
||||
if (after)
|
||||
info->flags |= G_CONNECT_AFTER;
|
||||
@@ -629,12 +682,303 @@ parse_signal (ParserData *data,
|
||||
info->tag.name = element_name;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *tmpl_class;
|
||||
gboolean found, done, in_tmpl;
|
||||
GString *xml;
|
||||
} TemplateParseData;
|
||||
|
||||
static void
|
||||
extract_template_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TemplateParseData *state = user_data;
|
||||
gint i;
|
||||
|
||||
if (state->done) return;
|
||||
|
||||
if (g_strcmp0 (element_name, "template") == 0)
|
||||
{
|
||||
for (i = 0; attribute_names[i]; i++)
|
||||
{
|
||||
if (!g_strcmp0 (attribute_names[i], "class"))
|
||||
state->found = (g_strcmp0 (attribute_values[i], state->tmpl_class) == 0);
|
||||
}
|
||||
|
||||
if (state->found)
|
||||
{
|
||||
state->in_tmpl = TRUE;
|
||||
g_string_append_printf (state->xml, "<external-object class=\"%s\" id=\"%s\">",
|
||||
state->tmpl_class,
|
||||
state->tmpl_class);
|
||||
return;
|
||||
}
|
||||
else
|
||||
g_string_append_printf (state->xml, "<%s", element_name);
|
||||
}
|
||||
else
|
||||
g_string_append_printf (state->xml, "<%s", element_name);
|
||||
|
||||
for (i = 0; attribute_names[i]; i++)
|
||||
{
|
||||
g_string_append_printf (state->xml, " %s=\"%s\"",
|
||||
attribute_names[i], attribute_values[i]);
|
||||
}
|
||||
g_string_append_printf (state->xml, ">");
|
||||
}
|
||||
|
||||
static void
|
||||
extract_template_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TemplateParseData *state = user_data;
|
||||
|
||||
if (state->done) return;
|
||||
|
||||
if (g_strcmp0 (element_name, "template") == 0 && state->in_tmpl)
|
||||
{
|
||||
state->in_tmpl = FALSE;
|
||||
g_string_append (state->xml, "</external-object>");
|
||||
}
|
||||
else
|
||||
g_string_append_printf (state->xml, "</%s>", element_name);
|
||||
|
||||
if (g_strcmp0 (element_name, "interface") == 0 && state->found)
|
||||
state->done = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
extract_template_text (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TemplateParseData *state = user_data;
|
||||
|
||||
if (state->done) return;
|
||||
|
||||
g_string_append_len (state->xml, text, text_len);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
extract_template (const gchar *buffer, const gchar *class_name)
|
||||
{
|
||||
GMarkupParser parser = { extract_template_start_element, extract_template_end_element, extract_template_text };
|
||||
TemplateParseData state = { class_name, FALSE, FALSE, FALSE, g_string_new ("")};
|
||||
GMarkupParseContext *context;
|
||||
|
||||
context = g_markup_parse_context_new (&parser,
|
||||
G_MARKUP_TREAT_CDATA_AS_TEXT |
|
||||
G_MARKUP_PREFIX_ERROR_POSITION,
|
||||
&state, NULL);
|
||||
|
||||
g_markup_parse_context_parse (context, buffer, -1, NULL);
|
||||
g_markup_parse_context_end_parse (context, NULL);
|
||||
g_markup_parse_context_free (context);
|
||||
|
||||
if (state.done)
|
||||
{
|
||||
gchar *retval = state.xml->str;
|
||||
g_string_free (state.xml, FALSE);
|
||||
g_file_set_contents ("/tmp/a.dump", retval, -1, NULL);
|
||||
return retval;
|
||||
}
|
||||
|
||||
g_string_free (state.xml, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GTypeInfo *info;
|
||||
gchar *tmpl;
|
||||
} TmplClassData;
|
||||
|
||||
static void
|
||||
composite_template_derived_class_init (gpointer g_class, gpointer class_data)
|
||||
{
|
||||
TmplClassData *data = class_data;
|
||||
gtk_container_class_set_template_from_string (g_class, data->tmpl,
|
||||
G_OBJECT_CLASS_NAME (g_class));
|
||||
}
|
||||
|
||||
static GType
|
||||
create_inline_type (GType parent_type,
|
||||
const gchar *class_name,
|
||||
const gchar *template_xml)
|
||||
{
|
||||
TmplClassData *tmpl;
|
||||
GTypeQuery query;
|
||||
GTypeInfo *info;
|
||||
|
||||
g_type_query (parent_type, &query);
|
||||
|
||||
tmpl = g_new0 (TmplClassData, 1);
|
||||
tmpl->info = info = g_new0 (GTypeInfo, 1);
|
||||
tmpl->tmpl = extract_template (template_xml, class_name);
|
||||
|
||||
info->class_size = query.class_size;
|
||||
info->class_init = composite_template_derived_class_init;
|
||||
info->class_data = tmpl; /* Let it leak! */
|
||||
info->instance_size = query.instance_size;
|
||||
|
||||
return g_type_register_static (parent_type, class_name, info, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_template (ParserData *data,
|
||||
const gchar *element_name,
|
||||
const gchar **names,
|
||||
const gchar **values,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *parent_class = NULL;
|
||||
const gchar *class_name = NULL;
|
||||
const GSList *l, *p;
|
||||
GType parent_type;
|
||||
gint i;
|
||||
|
||||
data->template_level++;
|
||||
|
||||
if (data->template_level > 1 ||
|
||||
!((l = g_markup_parse_context_get_element_stack (data->ctx)) &&
|
||||
(p = g_slist_next (l)) && g_strcmp0 (p->data, "interface") == 0))
|
||||
{
|
||||
error_generic (error, GTK_BUILDER_ERROR_INVALID_TAG, data,
|
||||
element_name, "non toplevel template found");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (names[i], "class") == 0)
|
||||
class_name = values[i];
|
||||
else if (strcmp (names[i], "parent") == 0)
|
||||
parent_class = values[i];
|
||||
else
|
||||
{
|
||||
error_invalid_attribute (data, element_name, names[i], error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_name)
|
||||
{
|
||||
error_missing_attribute (data, element_name, "class", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parent_class)
|
||||
{
|
||||
error_missing_attribute (data, element_name, "parent", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_type_from_name (class_name))
|
||||
{
|
||||
error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
|
||||
element_name, "template class '%s' already registered", class_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(parent_type = gtk_builder_get_type_from_name (data->builder, parent_class)))
|
||||
{
|
||||
error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
|
||||
element_name, "invalid parent class type found '%s'", parent_class);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate inline type */
|
||||
create_inline_type (parent_type, class_name, data->buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_external_object (ParserData *data,
|
||||
const gchar *element_name,
|
||||
const gchar **names,
|
||||
const gchar **values,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *class_name = NULL;
|
||||
const gchar *id = NULL;
|
||||
GObject *parent;
|
||||
gint i;
|
||||
|
||||
data->in_external_object = TRUE;
|
||||
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (names[i], "class") == 0)
|
||||
class_name = values[i];
|
||||
else if (strcmp (names[i], "id") == 0)
|
||||
id = values[i];
|
||||
else if (strcmp (names[i], "parent") == 0);
|
||||
else
|
||||
{
|
||||
error_invalid_attribute (data, element_name, names[i], error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_name)
|
||||
{
|
||||
error_missing_attribute (data, element_name, "class", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!id)
|
||||
{
|
||||
error_missing_attribute (data, element_name, "id", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->requested_objects == NULL &&
|
||||
(parent = gtk_builder_get_object (data->builder, id)))
|
||||
{
|
||||
GType class_type, parent_type = G_OBJECT_TYPE (parent);
|
||||
ObjectInfo *object_info;
|
||||
|
||||
if (!(class_type = g_type_from_name (class_name)))
|
||||
{
|
||||
error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
|
||||
element_name, "invalid class type found '%s'", class_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_type_is_a (parent_type, class_type))
|
||||
{
|
||||
error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
|
||||
element_name, "this template is for a class type %s not for %s",
|
||||
class_name, G_OBJECT_TYPE_NAME (parent));
|
||||
return;
|
||||
}
|
||||
|
||||
/* push parent to build its children from the template */
|
||||
object_info = g_slice_new0 (ObjectInfo);
|
||||
object_info->object = data->external_object = parent;
|
||||
object_info->object_type = parent_type;
|
||||
object_info->id = g_strdup (_gtk_builder_object_get_name (parent));
|
||||
object_info->tag.name = "object";
|
||||
|
||||
state_push (data, object_info);
|
||||
|
||||
parser_add_object_id (data, object_info->id, error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called by GtkBuilder */
|
||||
void
|
||||
_free_signal_info (SignalInfo *info,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_free (info->name);
|
||||
g_free (info->handler);
|
||||
g_free (info->connect_object_name);
|
||||
g_free (info->object_name);
|
||||
@@ -875,9 +1219,15 @@ start_element (GMarkupParseContext *context,
|
||||
|
||||
if (strcmp (element_name, "requires") == 0)
|
||||
parse_requires (data, element_name, names, values, error);
|
||||
else if (strcmp (element_name, "template") == 0)
|
||||
parse_template (data, element_name, names, values, error);
|
||||
else if (strcmp (element_name, "external-object") == 0)
|
||||
parse_external_object (data, element_name, names, values, error);
|
||||
else if (strcmp (element_name, "object") == 0)
|
||||
parse_object (context, data, element_name, names, values, error);
|
||||
else if (data->requested_objects && !data->inside_requested_object)
|
||||
else if ((data->requested_objects && !data->inside_requested_object) ||
|
||||
(data->in_external_object && !data->external_object) ||
|
||||
data->template_level)
|
||||
{
|
||||
/* If outside a requested object, simply ignore this tag */
|
||||
return;
|
||||
@@ -963,9 +1313,35 @@ end_element (GMarkupParseContext *context,
|
||||
else if (strcmp (element_name, "interface") == 0)
|
||||
{
|
||||
}
|
||||
else if (data->requested_objects && !data->inside_requested_object)
|
||||
else if (strcmp (element_name, "template") == 0)
|
||||
{
|
||||
/* If outside a requested object, simply ignore this tag */
|
||||
data->template_level--;
|
||||
}
|
||||
else if (strcmp (element_name, "external-object") == 0)
|
||||
{
|
||||
data->in_external_object = FALSE;
|
||||
|
||||
if (data->external_object)
|
||||
{
|
||||
ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
|
||||
|
||||
object_info->properties = g_slist_reverse (object_info->properties);
|
||||
|
||||
/* This is just to apply properties to the external object */
|
||||
_gtk_builder_construct (data->builder, object_info, error);
|
||||
|
||||
if (object_info->signals)
|
||||
_gtk_builder_add_signals (data->builder, object_info->signals);
|
||||
|
||||
free_object_info (object_info);
|
||||
data->external_object = NULL;
|
||||
}
|
||||
}
|
||||
else if ((data->requested_objects && !data->inside_requested_object) ||
|
||||
(data->in_external_object && !data->external_object) ||
|
||||
data->template_level)
|
||||
{
|
||||
/* If outside a requested object or template, simply ignore this tag */
|
||||
return;
|
||||
}
|
||||
else if (strcmp (element_name, "menu") == 0)
|
||||
@@ -1144,6 +1520,7 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
|
||||
domain = gtk_builder_get_translation_domain (builder);
|
||||
|
||||
data = g_new0 (ParserData, 1);
|
||||
data->buffer = buffer;
|
||||
data->builder = builder;
|
||||
data->filename = filename;
|
||||
data->domain = g_strdup (domain);
|
||||
|
@@ -31,7 +31,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
TagInfo tag;
|
||||
gchar *class_name;
|
||||
GType object_type;
|
||||
gchar *id;
|
||||
gchar *constructor;
|
||||
GSList *properties;
|
||||
@@ -58,17 +58,17 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
TagInfo tag;
|
||||
gchar *name;
|
||||
const gchar *name; /* Intern string */
|
||||
GString *text;
|
||||
gchar *data;
|
||||
gboolean translatable;
|
||||
gchar *context;
|
||||
guint8 translatable : 1;
|
||||
} PropertyInfo;
|
||||
|
||||
typedef struct {
|
||||
TagInfo tag;
|
||||
gchar *object_name;
|
||||
gchar *name;
|
||||
const gchar *name; /* Intern string */
|
||||
gchar *handler;
|
||||
GConnectFlags flags;
|
||||
gchar *connect_object_name;
|
||||
@@ -91,6 +91,7 @@ typedef struct {
|
||||
} SubParser;
|
||||
|
||||
typedef struct {
|
||||
const gchar *buffer;
|
||||
const gchar *last_element;
|
||||
GtkBuilder *builder;
|
||||
gchar *domain;
|
||||
@@ -107,17 +108,21 @@ typedef struct {
|
||||
gint cur_object_level;
|
||||
|
||||
GHashTable *object_ids;
|
||||
|
||||
GObject *external_object;
|
||||
gint in_external_object;
|
||||
gint template_level;
|
||||
} ParserData;
|
||||
|
||||
typedef GType (*GTypeGetFunc) (void);
|
||||
|
||||
/* Things only GtkBuilder should use */
|
||||
void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
|
||||
const gchar *filename,
|
||||
const gchar *buffer,
|
||||
gsize length,
|
||||
gchar **requested_objs,
|
||||
GError **error);
|
||||
void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
|
||||
const gchar *filename,
|
||||
const gchar *buffer,
|
||||
gsize length,
|
||||
gchar **requested_objs,
|
||||
GError **error);
|
||||
GObject * _gtk_builder_construct (GtkBuilder *builder,
|
||||
ObjectInfo *info,
|
||||
GError **error);
|
||||
@@ -159,5 +164,9 @@ void _gtk_builder_menu_start (ParserData *parser_data,
|
||||
GError **error);
|
||||
void _gtk_builder_menu_end (ParserData *parser_data);
|
||||
|
||||
const gchar * _gtk_builder_object_get_name (GObject *object);
|
||||
|
||||
void _gtk_builder_set_ignore_type (GtkBuilder *builder, GType ignore_type);
|
||||
GType _gtk_builder_get_ignore_type (GtkBuilder *builder);
|
||||
|
||||
#endif /* __GTK_BUILDER_PRIVATE_H__ */
|
||||
|
@@ -231,6 +231,36 @@
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar *name;
|
||||
GType type;
|
||||
guint offset;
|
||||
gboolean private;
|
||||
} InternalChildData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar *name;
|
||||
GObject *object;
|
||||
} InternalChild;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMPL_STRING,
|
||||
TMPL_RESOURCE
|
||||
} GtkContainerTemplateType;
|
||||
|
||||
struct _GtkContainerClassPrivate
|
||||
{
|
||||
GSList *tmpl_classes;
|
||||
|
||||
const gchar *tmpl, *tmpl_id;
|
||||
glong tmpl_len;
|
||||
GtkContainerTemplateType tmpl_type;
|
||||
GtkBuilderConnectFunc connect_func;
|
||||
GList *internal_children; /* InternalChildData list */
|
||||
};
|
||||
|
||||
struct _GtkContainerPrivate
|
||||
{
|
||||
@@ -244,6 +274,8 @@ struct _GtkContainerPrivate
|
||||
guint restyle_pending : 1;
|
||||
guint resize_mode : 2;
|
||||
guint request_mode : 2;
|
||||
|
||||
GArray *internal_children; /* InternalChild array */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -271,6 +303,9 @@ static void gtk_container_base_class_finalize (GtkContainerClass *klass);
|
||||
static void gtk_container_class_init (GtkContainerClass *klass);
|
||||
static void gtk_container_init (GtkContainer *container);
|
||||
static void gtk_container_destroy (GtkWidget *widget);
|
||||
static GObject *gtk_container_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties);
|
||||
static void gtk_container_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
@@ -390,6 +425,8 @@ gtk_container_get_type (void)
|
||||
GTK_TYPE_BUILDABLE,
|
||||
&buildable_info);
|
||||
|
||||
g_type_add_class_private (container_type, sizeof (GtkContainerClassPrivate));
|
||||
|
||||
}
|
||||
|
||||
return container_type;
|
||||
@@ -398,7 +435,19 @@ gtk_container_get_type (void)
|
||||
static void
|
||||
gtk_container_base_class_init (GtkContainerClass *class)
|
||||
{
|
||||
GtkContainerClassPrivate *priv;
|
||||
|
||||
/* reset instance specifc class fields that don't get inherited */
|
||||
class->priv = priv = G_TYPE_CLASS_GET_PRIVATE (class,
|
||||
GTK_TYPE_CONTAINER,
|
||||
GtkContainerClassPrivate);
|
||||
|
||||
priv->tmpl = NULL;
|
||||
priv->tmpl_id = NULL;
|
||||
priv->tmpl_classes = NULL;
|
||||
priv->connect_func = NULL;
|
||||
priv->internal_children = NULL;
|
||||
|
||||
class->set_child_property = NULL;
|
||||
class->get_child_property = NULL;
|
||||
}
|
||||
@@ -406,6 +455,7 @@ gtk_container_base_class_init (GtkContainerClass *class)
|
||||
static void
|
||||
gtk_container_base_class_finalize (GtkContainerClass *class)
|
||||
{
|
||||
GtkContainerClassPrivate *priv = class->priv;
|
||||
GList *list, *node;
|
||||
|
||||
list = g_param_spec_pool_list_owned (_gtk_widget_child_property_pool, G_OBJECT_CLASS_TYPE (class));
|
||||
@@ -418,6 +468,8 @@ gtk_container_base_class_finalize (GtkContainerClass *class)
|
||||
g_param_spec_unref (pspec);
|
||||
}
|
||||
g_list_free (list);
|
||||
|
||||
g_slist_free (priv->tmpl_classes);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -431,6 +483,7 @@ gtk_container_class_init (GtkContainerClass *class)
|
||||
vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
|
||||
hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
|
||||
|
||||
gobject_class->constructor = gtk_container_constructor;
|
||||
gobject_class->set_property = gtk_container_set_property;
|
||||
gobject_class->get_property = gtk_container_get_property;
|
||||
|
||||
@@ -520,10 +573,37 @@ gtk_container_class_init (GtkContainerClass *class)
|
||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_CONTAINER_ACCESSIBLE);
|
||||
}
|
||||
|
||||
static GObject *
|
||||
gtk_container_buildable_get_internal_child (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
const gchar *childname)
|
||||
{
|
||||
GArray *internal_children;
|
||||
|
||||
g_return_val_if_fail (childname && childname[0], NULL);
|
||||
|
||||
if ((internal_children = GTK_CONTAINER (buildable)->priv->internal_children))
|
||||
{
|
||||
gint i, len;
|
||||
|
||||
for (i = 0, len = internal_children->len; i < len; i++)
|
||||
{
|
||||
InternalChild *data = &g_array_index (internal_children, InternalChild, i);
|
||||
|
||||
if (g_strcmp0 (data->name, childname) == 0) return data->object;
|
||||
}
|
||||
}
|
||||
|
||||
return parent_buildable_iface->get_internal_child (buildable,
|
||||
builder,
|
||||
childname);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_buildable_init (GtkBuildableIface *iface)
|
||||
{
|
||||
parent_buildable_iface = g_type_interface_peek_parent (iface);
|
||||
iface->get_internal_child = gtk_container_buildable_get_internal_child;
|
||||
iface->add_child = gtk_container_buildable_add_child;
|
||||
iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
|
||||
iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
|
||||
@@ -1319,6 +1399,152 @@ gtk_container_class_list_child_properties (GObjectClass *cclass,
|
||||
return pspecs;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_class_set_template (GtkContainerClass *container_class,
|
||||
const gchar *tmpl,
|
||||
const gchar *template_id,
|
||||
GtkContainerTemplateType tmpl_type)
|
||||
{
|
||||
GtkContainerClassPrivate *priv = container_class->priv;
|
||||
GObjectClass *oclass;
|
||||
|
||||
priv->tmpl = tmpl;
|
||||
priv->tmpl_len = g_utf8_strlen (tmpl, -1);
|
||||
priv->tmpl_id = template_id;
|
||||
priv->tmpl_type = tmpl_type;
|
||||
|
||||
if (priv->tmpl_classes)
|
||||
{
|
||||
g_slist_free (priv->tmpl_classes);
|
||||
priv->tmpl_classes = NULL;
|
||||
}
|
||||
|
||||
/* Collect an ordered list of class which have templates to build */
|
||||
for (oclass = G_OBJECT_CLASS (container_class);
|
||||
GTK_IS_CONTAINER_CLASS (oclass);
|
||||
oclass = g_type_class_peek_parent (oclass))
|
||||
{
|
||||
GtkContainerClassPrivate *cpriv = GTK_CONTAINER_CLASS (oclass)->priv;
|
||||
|
||||
if (cpriv->tmpl)
|
||||
priv->tmpl_classes = g_slist_prepend (priv->tmpl_classes, oclass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_container_class_set_template_from_string:
|
||||
* @container_class: a #GtkContainerClass
|
||||
* @template_string: the #GtkBuilder xml string
|
||||
* @template_id: the template id
|
||||
*
|
||||
* For type implementations it is recommended to use #gtk_container_class_set_template_from_resource
|
||||
* instead of this function.
|
||||
*
|
||||
* Since: 3.8
|
||||
*/
|
||||
void
|
||||
gtk_container_class_set_template_from_string (GtkContainerClass *container_class,
|
||||
const gchar *template_string,
|
||||
const gchar *template_id)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONTAINER_CLASS (container_class));
|
||||
g_return_if_fail (template_string && template_string[0]);
|
||||
g_return_if_fail (template_id && template_id[0]);
|
||||
|
||||
gtk_container_class_set_template (container_class, template_string,
|
||||
template_id, TMPL_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_container_class_set_template_from_resource:
|
||||
* @container_class: a #GtkContainerClass
|
||||
* @resource_path: the #GtkBuilder xml resource path
|
||||
* @template_id: the template id
|
||||
*
|
||||
* This is used when implementing new composite widget types
|
||||
* to specify a UI template for instances of this type.
|
||||
*
|
||||
* Templates are in the <link linkend="BUILDER-UI">GtkBuilder UI description</link>
|
||||
* format and are used to implement composite widget types in
|
||||
* an automated way.
|
||||
*
|
||||
* Instances with an assigned template will have their children built at object
|
||||
* construct time.
|
||||
*
|
||||
* The provided xml is expected to have a <external-object> tag instead of
|
||||
* <object> with id=@template_id.
|
||||
*
|
||||
* Since: 3.8
|
||||
*/
|
||||
void
|
||||
gtk_container_class_set_template_from_resource (GtkContainerClass *container_class,
|
||||
const gchar *resource_path,
|
||||
const gchar *template_id)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONTAINER_CLASS (container_class));
|
||||
g_return_if_fail (resource_path && resource_path[0]);
|
||||
g_return_if_fail (template_id && template_id[0]);
|
||||
|
||||
gtk_container_class_set_template (container_class, resource_path,
|
||||
template_id, TMPL_RESOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_container_class_set_connect_func:
|
||||
* @container_class: a #GtkContainerClass
|
||||
* @connect_func: the #GtkBuilderConnectFunc to use when connecting signals internally.
|
||||
*
|
||||
* Sets the function to be used when automatically connecting signals
|
||||
* defined by this class's GtkBuilder template.
|
||||
*
|
||||
* Since: 3.6
|
||||
*/
|
||||
void
|
||||
gtk_container_class_set_connect_func (GtkContainerClass *container_class,
|
||||
GtkBuilderConnectFunc connect_func)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONTAINER_CLASS(container_class));
|
||||
g_return_if_fail (connect_func != NULL);
|
||||
|
||||
container_class->priv->connect_func = connect_func;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_container_class_declare_internal_child:
|
||||
* @container_class: a #GtkContainerClass
|
||||
* @use_private: True if struct_offset refers to the instance private struct
|
||||
* @struct_offset: offset where to save composite children pointer
|
||||
* @name: the name of the composite children to declare
|
||||
*
|
||||
* Declare a child defined in the template as an internal children.
|
||||
* Use #G_STRUCT_OFFSET to pass in the struct_offset of the pointer that will be set automatically on construction.
|
||||
* If you do not need to keep a pointer set use_private to FALSE and struct_offset to 0.
|
||||
*
|
||||
* Since: 3.6
|
||||
*/
|
||||
void
|
||||
gtk_container_class_declare_internal_child (GtkContainerClass *container_class,
|
||||
gboolean use_private,
|
||||
guint struct_offset,
|
||||
const gchar *name)
|
||||
{
|
||||
GtkContainerClassPrivate *priv;
|
||||
InternalChildData *child;
|
||||
|
||||
g_return_if_fail (GTK_IS_CONTAINER_CLASS (container_class));
|
||||
g_return_if_fail (name);
|
||||
|
||||
priv = container_class->priv;
|
||||
|
||||
child = g_new0 (InternalChildData, 1);
|
||||
child->name = g_strdup (name);
|
||||
child->private = use_private;
|
||||
child->type = G_TYPE_FROM_CLASS (container_class);
|
||||
child->offset = struct_offset;
|
||||
|
||||
priv->internal_children = g_list_prepend (priv->internal_children, child);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_add_unimplemented (GtkContainer *container,
|
||||
GtkWidget *widget)
|
||||
@@ -1347,6 +1573,7 @@ gtk_container_init (GtkContainer *container)
|
||||
priv->border_width = 0;
|
||||
priv->resize_mode = GTK_RESIZE_PARENT;
|
||||
priv->reallocate_redraws = FALSE;
|
||||
priv->internal_children = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1375,11 +1602,133 @@ gtk_container_destroy (GtkWidget *widget)
|
||||
if (priv->has_focus_chain)
|
||||
gtk_container_unset_focus_chain (container);
|
||||
|
||||
if (priv->internal_children)
|
||||
{
|
||||
GArray *internal_children = priv->internal_children;
|
||||
gint i, len = internal_children->len;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
InternalChild *data = &g_array_index (internal_children, InternalChild, i);
|
||||
g_object_unref (data->object);
|
||||
}
|
||||
g_array_unref (internal_children);
|
||||
priv->internal_children = NULL;
|
||||
}
|
||||
|
||||
gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_child_set_internal (GtkContainer *container,
|
||||
InternalChildData *child,
|
||||
GObject *internal)
|
||||
{
|
||||
GtkContainerPrivate *priv = container->priv;
|
||||
InternalChild data;
|
||||
GObject **retval;
|
||||
|
||||
if (!priv->internal_children)
|
||||
priv->internal_children = g_array_new (FALSE, FALSE, sizeof (InternalChild));
|
||||
|
||||
if (GTK_IS_WIDGET (internal))
|
||||
gtk_widget_set_composite_name (GTK_WIDGET (internal), child->name);
|
||||
|
||||
data.name = child->name;
|
||||
data.object = g_object_ref (internal);
|
||||
g_array_append_val (priv->internal_children, data);
|
||||
|
||||
if (child->private)
|
||||
{
|
||||
gpointer pstruct = G_TYPE_INSTANCE_GET_PRIVATE (container, child->type, gpointer);
|
||||
retval = G_STRUCT_MEMBER_P (pstruct, child->offset);
|
||||
}
|
||||
else
|
||||
retval = G_STRUCT_MEMBER_P (container, child->offset);
|
||||
|
||||
*retval = internal;
|
||||
}
|
||||
|
||||
static GObject *
|
||||
gtk_container_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
GtkContainerClassPrivate *priv;
|
||||
GtkContainer *container;
|
||||
GError *error = NULL;
|
||||
GtkBuilder *builder;
|
||||
GObject *object;
|
||||
GSList *l;
|
||||
|
||||
object = G_OBJECT_CLASS (parent_class)->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties);
|
||||
|
||||
priv = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (object))->priv;
|
||||
container = GTK_CONTAINER (object);
|
||||
|
||||
gtk_widget_push_composite_child ();
|
||||
|
||||
/* Build the templates for each class starting with the superclass descending */
|
||||
for (l = priv->tmpl_classes; l; l = g_slist_next (l))
|
||||
{
|
||||
GtkContainerClassPrivate *cpriv = GTK_CONTAINER_CLASS (l->data)->priv;
|
||||
GList *children;
|
||||
guint ret;
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_expose_object (builder, cpriv->tmpl_id, object);
|
||||
/* Safeguard to avoid recursion */
|
||||
_gtk_builder_set_ignore_type (builder, type);
|
||||
|
||||
if (cpriv->tmpl_type == TMPL_STRING)
|
||||
ret = gtk_builder_add_from_string (builder, cpriv->tmpl, cpriv->tmpl_len, &error);
|
||||
else if (cpriv->tmpl_type == TMPL_RESOURCE)
|
||||
ret = gtk_builder_add_from_resource (builder, cpriv->tmpl, &error);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
/* Setup internal children */
|
||||
for (children = cpriv->internal_children; children; children = g_list_next (children))
|
||||
{
|
||||
InternalChildData *child = children->data;
|
||||
GObject *internal;
|
||||
|
||||
if ((internal = gtk_builder_get_object (builder, child->name)))
|
||||
gtk_container_child_set_internal (container, child, internal);
|
||||
else
|
||||
{
|
||||
g_warning ("Unable to setup internal child %s while building GtkContainer class %s",
|
||||
g_type_name (type), child->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpriv->connect_func)
|
||||
gtk_builder_connect_signals_full (builder, cpriv->connect_func, container);
|
||||
else
|
||||
gtk_builder_connect_signals (builder, container);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_critical ("Unable to build GtkContainer class %s from template: %s",
|
||||
g_type_name (type), error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
gtk_widget_pop_composite_child ();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_container_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
|
@@ -31,6 +31,8 @@
|
||||
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtkadjustment.h>
|
||||
#include <gtk/gtkbuilder.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -46,6 +48,7 @@ G_BEGIN_DECLS
|
||||
typedef struct _GtkContainer GtkContainer;
|
||||
typedef struct _GtkContainerPrivate GtkContainerPrivate;
|
||||
typedef struct _GtkContainerClass GtkContainerClass;
|
||||
typedef struct _GtkContainerClassPrivate GtkContainerClassPrivate;
|
||||
|
||||
struct _GtkContainer
|
||||
{
|
||||
@@ -91,6 +94,8 @@ struct _GtkContainerClass
|
||||
|
||||
unsigned int _handle_border_width : 1;
|
||||
|
||||
GtkContainerClassPrivate *priv;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
@@ -99,7 +104,6 @@ struct _GtkContainerClass
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
|
||||
@@ -219,6 +223,20 @@ void gtk_container_forall (GtkContainer *container,
|
||||
|
||||
void gtk_container_class_handle_border_width (GtkContainerClass *klass);
|
||||
|
||||
/* Class-level functions */
|
||||
void gtk_container_class_set_template_from_string (GtkContainerClass *container_class,
|
||||
const gchar *template_string,
|
||||
const gchar *template_id);
|
||||
void gtk_container_class_set_template_from_resource (GtkContainerClass *container_class,
|
||||
const gchar *resource_path,
|
||||
const gchar *template_id);
|
||||
void gtk_container_class_set_connect_func (GtkContainerClass *container_class,
|
||||
GtkBuilderConnectFunc connect_func);
|
||||
void gtk_container_class_declare_internal_child (GtkContainerClass *container_class,
|
||||
gboolean use_private,
|
||||
guint struct_offset,
|
||||
const gchar *name);
|
||||
|
||||
GtkWidgetPath * gtk_container_get_path_for_child (GtkContainer *container,
|
||||
GtkWidget *child);
|
||||
|
||||
|
@@ -2715,6 +2715,233 @@ test_level_bar (void)
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
static GObject *external_object = NULL, *external_object_swapped = NULL;
|
||||
|
||||
void
|
||||
on_button_clicked (GtkButton *button, GObject *data)
|
||||
{
|
||||
external_object = data;
|
||||
}
|
||||
|
||||
void
|
||||
on_button_clicked_swapped (GObject *data, GtkButton *button)
|
||||
{
|
||||
external_object_swapped = data;
|
||||
}
|
||||
|
||||
static void
|
||||
test_expose_object (void)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
GtkWidget *image;
|
||||
GObject *obj;
|
||||
const gchar buffer[] =
|
||||
"<interface>"
|
||||
" <object class=\"GtkButton\" id=\"button\">"
|
||||
" <property name=\"image\">external_image</property>"
|
||||
" <signal name=\"clicked\" handler=\"on_button_clicked\" object=\"builder\" swapped=\"no\"/>"
|
||||
" <signal name=\"clicked\" handler=\"on_button_clicked_swapped\" object=\"builder\"/>"
|
||||
" </object>"
|
||||
"</interface>";
|
||||
|
||||
image = gtk_image_new ();
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_expose_object (builder, "external_image", G_OBJECT (image));
|
||||
gtk_builder_expose_object (builder, "builder", G_OBJECT (builder));
|
||||
gtk_builder_add_from_string (builder, buffer, -1, &error);
|
||||
g_assert (error == NULL);
|
||||
|
||||
obj = gtk_builder_get_object (builder, "button");
|
||||
g_assert (GTK_IS_BUTTON (obj));
|
||||
|
||||
g_assert (gtk_button_get_image (GTK_BUTTON (obj)) == image);
|
||||
|
||||
/* Connect signals and fake clicked event */
|
||||
gtk_builder_connect_signals (builder, NULL);
|
||||
gtk_button_clicked (GTK_BUTTON (obj));
|
||||
|
||||
g_assert (external_object == G_OBJECT (builder));
|
||||
g_assert (external_object_swapped == G_OBJECT (builder));
|
||||
}
|
||||
|
||||
static void
|
||||
test_external_object_real (gboolean use_add_objects)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *mybox, *mygrid;
|
||||
gboolean expand = FALSE, fill = FALSE;
|
||||
GtkPackType pack_type = GTK_PACK_START;
|
||||
guint padding = 0;
|
||||
const gchar buffer[] =
|
||||
"<interface>\n"
|
||||
" <external-object class=\"GtkGrid\" id=\"mygrid\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkLabel\" id=\"gridlabel\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" </object>\n"
|
||||
" </child>\n"
|
||||
" </external-object>\n"
|
||||
/* This external_object should get ignored */
|
||||
" <external-object class=\"GtkGrid\" id=\"mygrid2\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkLabel\" id=\"grid2label\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" </object>\n"
|
||||
" </child>\n"
|
||||
" </external-object>\n"
|
||||
/* This is the external_object we are interested in! */
|
||||
" <external-object class=\"GtkBox\" id=\"mybox\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <property name=\"can_focus\">False</property>\n"
|
||||
" <property name=\"orientation\">vertical</property>\n"
|
||||
" <property name=\"spacing\">8</property>\n"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkLabel\" id=\"boxlabel\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <property name=\"can_focus\">False</property>\n"
|
||||
" <property name=\"label\" translatable=\"yes\">label</property>\n"
|
||||
" </object>\n"
|
||||
" <packing>\n"
|
||||
" <property name=\"expand\">True</property>\n"
|
||||
" <property name=\"fill\">True</property>\n"
|
||||
" <property name=\"padding\">16</property>\n"
|
||||
" <property name=\"pack-type\">GTK_PACK_END</property>\n"
|
||||
" <property name=\"position\">0</property>\n"
|
||||
" </packing>\n"
|
||||
" </child>\n"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkButton\" id=\"button\">\n"
|
||||
" <property name=\"label\" translatable=\"yes\">button</property>\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <property name=\"can_focus\">True</property>\n"
|
||||
" <property name=\"receives_default\">True</property>\n"
|
||||
" </object>\n"
|
||||
" <packing>\n"
|
||||
" <property name=\"expand\">False</property>\n"
|
||||
" <property name=\"fill\">True</property>\n"
|
||||
" <property name=\"position\">1</property>\n"
|
||||
" </packing>\n"
|
||||
" </child>\n"
|
||||
" </external-object>\n"
|
||||
" <object class=\"GtkWindow\" id=\"window\">"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkLabel\" id=\"winlabel\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" </object>\n"
|
||||
" </child>\n"
|
||||
" </object>"
|
||||
"</interface>";
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
mybox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
g_object_ref_sink (mybox);
|
||||
|
||||
mygrid = gtk_grid_new ();
|
||||
g_object_ref_sink (mygrid);
|
||||
|
||||
gtk_builder_expose_object (builder, "mybox", G_OBJECT (mybox));
|
||||
|
||||
if (use_add_objects)
|
||||
{
|
||||
gchar *objs[] = {"window", NULL};
|
||||
gtk_builder_add_objects_from_string (builder, buffer, -1, objs, &error);
|
||||
|
||||
if (error) g_warning ("%s", error->message);
|
||||
|
||||
/* Check if requested object creation works */
|
||||
g_assert (GTK_IS_WINDOW (gtk_builder_get_object (builder, "window")));
|
||||
|
||||
/* external objects should be ignored if we requested a specific object */
|
||||
g_assert (gtk_builder_get_object (builder, "winlabel"));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_builder_add_from_string (builder, buffer, -1, &error);
|
||||
|
||||
if (error) g_warning ("%s", error->message);
|
||||
g_assert (error == NULL);
|
||||
|
||||
/* Check template properties */
|
||||
g_assert (gtk_box_get_spacing (GTK_BOX (mybox)) == 8);
|
||||
g_assert (gtk_orientable_get_orientation (GTK_ORIENTABLE (mybox)) == GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
/* Check if children are built */
|
||||
g_assert (GTK_IS_LABEL (gtk_builder_get_object (builder, "boxlabel")));
|
||||
g_assert (GTK_IS_BUTTON (gtk_builder_get_object (builder, "button")));
|
||||
|
||||
/* Check child packing properties */
|
||||
gtk_box_query_child_packing (GTK_BOX (mybox),
|
||||
GTK_WIDGET (gtk_builder_get_object (builder, "boxlabel")),
|
||||
&expand, &fill, &padding, &pack_type);
|
||||
g_assert (expand);
|
||||
g_assert (fill);
|
||||
g_assert (padding == 16);
|
||||
g_assert (pack_type == GTK_PACK_END);
|
||||
}
|
||||
|
||||
g_object_unref (builder);
|
||||
g_object_unref (mybox);
|
||||
g_object_unref (mygrid);
|
||||
}
|
||||
|
||||
static void
|
||||
test_external_object (void)
|
||||
{
|
||||
test_external_object_real (FALSE);
|
||||
test_external_object_real (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_template ()
|
||||
{
|
||||
GError *error = NULL;
|
||||
GtkBuilder *builder;
|
||||
const gchar buffer[] =
|
||||
"<interface>\n"
|
||||
" <template class=\"MyGtkGrid\" parent=\"GtkGrid\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" <child>\n"
|
||||
" <object class=\"GtkLabel\" id=\"gridlabel\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" </object>\n"
|
||||
" </child>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n"
|
||||
"<interface>\n"
|
||||
" <object class=\"GtkWindow\" id=\"window\">"
|
||||
" <child>\n"
|
||||
" <object class=\"MyGtkGrid\" id=\"mygrid\">\n"
|
||||
" <property name=\"visible\">True</property>\n"
|
||||
" </object>\n"
|
||||
" </child>\n"
|
||||
" </object>\n"
|
||||
"</interface>\n";
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
|
||||
/* make sure the type we are trying to register does not exist */
|
||||
g_assert (!g_type_from_name ("MyGtkGrid"));
|
||||
|
||||
gtk_builder_add_from_string (builder, buffer, -1, &error);
|
||||
|
||||
if (error) g_warning ("%s", error->message);
|
||||
g_assert (error == NULL);
|
||||
|
||||
/* Check if new type was registered on the fly! */
|
||||
g_assert (g_type_from_name ("MyGtkGrid"));
|
||||
|
||||
g_assert (GTK_IS_WINDOW (gtk_builder_get_object (builder, "window")));
|
||||
|
||||
/* Check if inline derived child was built */
|
||||
g_assert (GTK_IS_GRID (gtk_builder_get_object (builder, "mygrid")));
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -2763,6 +2990,9 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/Builder/MessageDialog", test_message_dialog);
|
||||
g_test_add_func ("/Builder/GMenu", test_gmenu);
|
||||
g_test_add_func ("/Builder/LevelBar", test_level_bar);
|
||||
g_test_add_func ("/Builder/Expose Object", test_expose_object);
|
||||
g_test_add_func ("/Builder/External Object", test_external_object);
|
||||
g_test_add_func ("/Builder/Template", test_template);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
Reference in New Issue
Block a user