Commit 96a3fe3b authored by Tristan Van Berkom's avatar Tristan Van Berkom

Implement property lookups with a hash table, fixed mem leaks


	* gladeui/glade-widget.c: Implement property lookups with a hash table, fixed mem leaks

	* gladeui/glade-property.c: Read properties from the passed node directly, fixed mem leaks

	* gladeui/glade-widget-adaptor.c: Read properties in the order they are listed in the file, 
	not by the order of the properties in the object (helps load performance).

	* gladeui/glade-project.c: Fixed mem leaks, release widget property references before
	destroying all the glade widgets.


svn path=/trunk/; revision=1985
parent 5018c669
......@@ -9,6 +9,16 @@
* gladeui/glade-project.c: Fixed regression, now the inspector updates on widget
name changes.
* gladeui/glade-widget.c: Implement property lookups with a hash table, fixed mem leaks
* gladeui/glade-property.c: Read properties from the passed node directly, fixed mem leaks
* gladeui/glade-widget-adaptor.c: Read properties in the order they are listed in the file,
not by the order of the properties in the object (helps load performance).
* gladeui/glade-project.c: Fixed mem leaks, release widget property references before
destroying all the glade widgets.
2008-10-20 Tristan Van Berkom <tvb@gnome.org>
......
......@@ -242,9 +242,10 @@ glade_project_list_unref (GList *original_list)
static void
glade_project_dispose (GObject *object)
{
GladeProject *project = GLADE_PROJECT (object);
GList *list;
GladeWidget *gwidget;
GladeProject *project = GLADE_PROJECT (object);
GList *list;
GladeWidget *gwidget;
GladeProperty *property;
/* Emit close signal */
g_signal_emit (object, glade_project_signals [CLOSE], 0);
......@@ -268,13 +269,19 @@ glade_project_dispose (GObject *object)
gwidget->parent->object,
gwidget->object))
glade_widget_remove_child (gwidget->parent, gwidget);
/* Release references by way of object properties... */
while (gwidget->prop_refs)
{
property = GLADE_PROPERTY (gwidget->prop_refs->data);
glade_property_set (property, NULL);
}
}
/* Remove objects from the project */
for (list = project->priv->objects; list; list = list->next)
{
gwidget = glade_widget_get_from_gobject (list->data);
g_object_unref (G_OBJECT (list->data)); /* Remove the GladeProject reference */
g_object_unref (G_OBJECT (gwidget)); /* Remove the overall "Glade" reference */
}
......
......@@ -488,6 +488,12 @@ glade_property_finalize (GObject *object)
}
if (property->i18n_comment)
g_free (property->i18n_comment);
if (property->i18n_context)
g_free (property->i18n_context);
if (property->support_warning)
g_free (property->support_warning);
if (property->insensitive_tooltip)
g_free (property->insensitive_tooltip);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
......@@ -992,152 +998,79 @@ glade_property_load (GladeProperty *property)
void
glade_property_read (GladeProperty *property,
GladeProject *project,
GladeXmlNode *node)
GladeXmlNode *prop)
{
GladeProjectFormat fmt;
GladeXmlNode *prop;
GValue *gvalue = NULL;
gchar *id, *name, *value;
gchar /* *id, *name, */ *value;
const gchar *search_name;
gint translatable, has_context;
gchar *comment = NULL, *context = NULL;
g_return_if_fail (GLADE_IS_PROPERTY (property));
g_return_if_fail (GLADE_IS_PROJECT (project));
g_return_if_fail (node != NULL);
g_return_if_fail (prop != NULL);
fmt = glade_project_get_format (project);
/* This code should work the same for <packing> and <widget> */
if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_PACKING) ||
glade_xml_node_verify_silent
(node, GLADE_XML_TAG_WIDGET (fmt))))
if (!glade_xml_node_verify (prop, GLADE_XML_TAG_PROPERTY))
return;
for (prop = glade_xml_node_get_children (node);
prop; prop = glade_xml_node_next (prop))
{
search_name = property->klass->id;
if (!glade_xml_node_verify_silent (prop, GLADE_XML_TAG_PROPERTY))
continue;
if (!(value = glade_xml_get_content (prop)))
return;
if (!(name = glade_xml_get_property_string_required
(prop, GLADE_XML_TAG_NAME, NULL)))
continue;
if (glade_property_class_is_object (property->klass, fmt))
{
/* we must synchronize this directly after loading this project
* (i.e. lookup the actual objects after they've been parsed and
* are present).
*/
g_object_set_data_full (G_OBJECT (property),
"glade-loaded-object",
g_strdup (value), g_free);
}
else
{
gvalue = glade_property_class_make_gvalue_from_string
(property->klass, value, project, property->widget);
if (!(value = glade_xml_get_content (prop)))
{
/* XXX should be glade_xml_get_content_required()... */
g_free (name);
g_free (value);
continue;
}
GLADE_PROPERTY_GET_KLASS
(property)->set_value (property, gvalue);
/* Switch up the values if we are using GtkIconFactory in builder
* to load some hacked out legacy pixbufs
*/
if (fmt == GLADE_PROJECT_FORMAT_GTKBUILDER)
{
gboolean is_loaded_value =
glade_project_is_loaded_factory_file (project, value);
if (property->klass->factory_stock_id && is_loaded_value)
search_name = property->klass->factory_stock_id;
/* If this property was loaded via another property, skip it... */
else if (glade_widget_has_factory_stock_id
(property->widget, property->klass->id) && is_loaded_value)
{
/* really ?... */
g_free (value);
g_free (name);
break;
}
}
g_value_unset (gvalue);
g_free (gvalue);
/* Make sure we are working with dashes and
* not underscores ...
/* If an optional property is specified in the
* glade file, its enabled
*/
id = glade_util_read_prop_name (name);
g_free (name);
if (!strcmp (id, search_name))
{
if (property && glade_property_class_is_object (property->klass, fmt))
{
/* we must synchronize this directly after loading this project
* (i.e. lookup the actual objects after they've been parsed and
* are present).
*/
g_object_set_data_full (G_OBJECT (property),
"glade-loaded-object",
g_strdup (value), g_free);
}
else
{
if (fmt == GLADE_PROJECT_FORMAT_GTKBUILDER &&
search_name == property->klass->factory_stock_id)
{
gchar *filename =
glade_util_icon_name_to_filename (value);
g_free (value);
value = filename;
}
gvalue = glade_property_class_make_gvalue_from_string
(property->klass, value, project, property->widget);
if (property)
{
GLADE_PROPERTY_GET_KLASS
(property)->set_value (property, gvalue);
}
g_value_unset (gvalue);
g_free (gvalue);
/* If an optional property is specified in the
* glade file, its enabled
*/
property->enabled = TRUE;
}
if (property)
{
gint translatable, has_context;
gchar *comment = NULL, *context = NULL;
translatable = glade_xml_get_property_boolean
(prop, GLADE_TAG_TRANSLATABLE, FALSE);
comment = glade_xml_get_property_string
(prop, GLADE_TAG_COMMENT);
if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
has_context = glade_xml_get_property_boolean
(prop, GLADE_TAG_HAS_CONTEXT, FALSE);
else
context = glade_xml_get_property_string
(prop, GLADE_TAG_CONTEXT);
glade_property_i18n_set_translatable (property, translatable);
glade_property_i18n_set_comment (property, comment);
if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
glade_property_i18n_set_has_context
(property, has_context);
else
glade_property_i18n_set_context
(property, context);
g_free (comment);
g_free (context);
}
g_free (value);
g_free (id);
break;
}
g_free (id);
property->enabled = TRUE;
}
translatable = glade_xml_get_property_boolean
(prop, GLADE_TAG_TRANSLATABLE, FALSE);
comment = glade_xml_get_property_string
(prop, GLADE_TAG_COMMENT);
if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
has_context = glade_xml_get_property_boolean
(prop, GLADE_TAG_HAS_CONTEXT, FALSE);
else
context = glade_xml_get_property_string
(prop, GLADE_TAG_CONTEXT);
glade_property_i18n_set_translatable (property, translatable);
glade_property_i18n_set_comment (property, comment);
if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
glade_property_i18n_set_has_context
(property, has_context);
else
glade_property_i18n_set_context
(property, context);
g_free (comment);
g_free (context);
g_free (value);
}
......
......@@ -848,38 +848,54 @@ glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *sig_node, *child_node;
GladeXmlNode *iter_node;
GList *props;
GladeSignal *signal;
GladeProperty *property;
gchar *name, *prop_name;
/* Read in the properties */
for (props = widget->properties;
props; props = props->next)
{
GladeProperty *property = props->data;
glade_property_read
(property, widget->project, node);
for (iter_node = glade_xml_node_get_children (node);
iter_node; iter_node = glade_xml_node_next (iter_node))
{
if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_PROPERTY))
continue;
/* Get prop name from node and lookup property ...*/
if (!(name = glade_xml_get_property_string_required
(iter_node, GLADE_XML_TAG_NAME, NULL)))
continue;
prop_name = glade_util_read_prop_name (name);
/* Some properties may be special child type of custom, just leave them for the adaptor */
if ((property = glade_widget_get_property (widget, prop_name)) != NULL)
glade_property_read (property, widget->project, iter_node);
g_free (prop_name);
g_free (name);
}
/* Read in the signals */
for (sig_node = glade_xml_node_get_children (node);
sig_node; sig_node = glade_xml_node_next (sig_node))
for (iter_node = glade_xml_node_get_children (node);
iter_node; iter_node = glade_xml_node_next (iter_node))
{
if (!glade_xml_node_verify_silent (sig_node, GLADE_XML_TAG_SIGNAL))
if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_SIGNAL))
continue;
if (!(signal = glade_signal_read (sig_node)))
if (!(signal = glade_signal_read (iter_node)))
continue;
glade_widget_add_signal_handler (widget, signal);
}
/* Read in children */
for (child_node = glade_xml_node_get_children (node);
child_node; child_node = glade_xml_node_next (child_node))
for (iter_node = glade_xml_node_get_children (node);
iter_node; iter_node = glade_xml_node_next (iter_node))
{
if (glade_xml_node_verify_silent (child_node, GLADE_XML_TAG_CHILD))
glade_widget_read_child (widget, child_node);
if (glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_CHILD))
glade_widget_read_child (widget, iter_node);
}
}
......@@ -952,10 +968,12 @@ glade_widget_adaptor_object_read_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *widget_node, *packing_node;
GladeXmlNode *widget_node, *packing_node, *iter_node;
GladeWidget *child_widget;
GList *packing;
gchar *internal_name;
gchar *name, *prop_name;
GladeProperty *property;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
return;
......@@ -986,15 +1004,28 @@ glade_widget_adaptor_object_read_child (GladeWidgetAdaptor *adaptor,
glade_xml_search_child
(node, GLADE_XML_TAG_PACKING)) != NULL)
{
/* Get the packing properties */
for (packing = child_widget->packing_properties;
packing; packing = packing->next)
/* Read in the properties */
for (iter_node = glade_xml_node_get_children (packing_node);
iter_node; iter_node = glade_xml_node_next (iter_node))
{
GladeProperty *property = packing->data;
glade_property_read (property,
child_widget->project,
packing_node);
if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_PROPERTY))
continue;
/* Get prop name from node and lookup property ...*/
if (!(name = glade_xml_get_property_string_required
(iter_node, GLADE_XML_TAG_NAME, NULL)))
continue;
prop_name = glade_util_read_prop_name (name);
/* Some properties may be special child type of custom,
* just leave them for the adaptor */
if ((property = glade_widget_get_pack_property (child_widget, prop_name)) != NULL)
glade_property_read (property, child_widget->project, iter_node);
g_free (prop_name);
g_free (name);
}
}
}
......
......@@ -746,8 +746,14 @@ glade_widget_finalize (GObject *object)
g_free (widget->name);
g_free (widget->internal);
g_free (widget->support_warning);
g_hash_table_destroy (widget->signals);
if (widget->props_hash)
g_hash_table_destroy (widget->props_hash);
if (widget->pack_props_hash)
g_hash_table_destroy (widget->pack_props_hash);
G_OBJECT_CLASS(glade_widget_parent_class)->finalize(object);
}
......@@ -761,6 +767,9 @@ glade_widget_dispose (GObject *object)
/* We do not keep a reference to internal widgets */
if (widget->internal == NULL)
{
g_print ("Destroying internal object (gtkobject %d), ref count %d\n",
GTK_IS_OBJECT (widget->object), widget->object->ref_count);
if (GTK_IS_OBJECT (widget->object))
gtk_object_destroy (GTK_OBJECT (widget->object));
else
......@@ -1616,13 +1625,18 @@ glade_widget_set_properties (GladeWidget *widget, GList *properties)
g_list_foreach (widget->properties, (GFunc)g_object_unref, NULL);
g_list_free (widget->properties);
}
if (widget->props_hash)
g_hash_table_destroy (widget->props_hash);
widget->properties = properties;
widget->props_hash = g_hash_table_new (g_str_hash, g_str_equal);
for (list = properties; list; list = list->next)
{
property = list->data;
property->widget = widget;
g_hash_table_insert (widget->props_hash, property->klass->id, property);
}
}
}
......@@ -1649,7 +1663,7 @@ glade_widget_set_adaptor (GladeWidget *widget, GladeWidgetAdaptor *adaptor)
{
GladePropertyClass *property_class;
GladeProperty *property;
GList *list;
GList *list, *properties = NULL;
g_return_if_fail (GLADE_IS_WIDGET (widget));
g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
......@@ -1672,10 +1686,9 @@ glade_widget_set_adaptor (GladeWidget *widget, GladeWidgetAdaptor *adaptor)
property_class->id);
continue;
}
widget->properties = g_list_prepend (widget->properties, property);
properties = g_list_prepend (properties, property);
}
widget->properties = g_list_reverse (widget->properties);
glade_widget_set_properties (widget, g_list_reverse (properties));
}
/* Create actions from adaptor */
......@@ -2486,22 +2499,16 @@ glade_widget_get_project (GladeWidget *widget)
GladeProperty *
glade_widget_get_property (GladeWidget *widget, const gchar *id_property)
{
static gchar id_buffer[GPC_PROPERTY_NAMELEN] = { 0, };
GList *list;
GladeProperty *property;
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
g_return_val_if_fail (id_property != NULL, NULL);
/* "-1" to always leave a trailing '\0' charachter */
strncpy (id_buffer, id_property, GPC_PROPERTY_NAMELEN - 1);
glade_util_replace (id_buffer, '_', '-');
for (list = widget->properties; list; list = list->next) {
property = list->data;
if (strcmp (property->klass->id, id_buffer) == 0)
return property;
}
if (widget->props_hash &&
(property = g_hash_table_lookup (widget->props_hash, id_property)))
return property;
return glade_widget_get_pack_property (widget, id_property);
}
......@@ -2515,22 +2522,16 @@ glade_widget_get_property (GladeWidget *widget, const gchar *id_property)
GladeProperty *
glade_widget_get_pack_property (GladeWidget *widget, const gchar *id_property)
{
static gchar id_buffer[GPC_PROPERTY_NAMELEN] = { 0, };
GList *list;
GladeProperty *property;
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
g_return_val_if_fail (id_property != NULL, NULL);
/* "-1" to always leave a trailing '\0' charachter */
strncpy (id_buffer, id_property, GPC_PROPERTY_NAMELEN - 1);
glade_util_replace (id_buffer, '_', '-');
if (widget->pack_props_hash &&
(property = g_hash_table_lookup (widget->pack_props_hash, id_property)))
return property;
for (list = widget->packing_properties; list; list = list->next) {
property = list->data;
if (strcmp (property->klass->id, id_buffer) == 0)
return property;
}
return NULL;
}
......@@ -3179,8 +3180,11 @@ glade_widget_set_object (GladeWidget *gwidget, GObject *new_object)
/* Add internal reference to new widget if its not internal */
if (gwidget->internal)
gwidget->object = G_OBJECT(new_object);
else
else if (GTK_IS_OBJECT (new_object))
gwidget->object = g_object_ref (G_OBJECT(new_object));
else
/* If this is a base GObject; assume ownership of the initial ref count */
gwidget->object = new_object;
g_object_set_qdata (G_OBJECT (new_object), glade_widget_name_quark, gwidget);
......@@ -3312,6 +3316,10 @@ glade_widget_set_packing_properties (GladeWidget *widget,
g_list_free (widget->packing_properties);
widget->packing_properties = NULL;
if (widget->pack_props_hash)
g_hash_table_destroy (widget->pack_props_hash);
widget->pack_props_hash = NULL;
/* We have to detect whether this is an anarchist child of a composite
* widget or not, in otherwords; whether its really a direct child or
* a child of a popup window created on the composite widget's behalf.
......@@ -3319,6 +3327,16 @@ glade_widget_set_packing_properties (GladeWidget *widget,
if (widget->anarchist) return;
widget->packing_properties = glade_widget_create_packing_properties (container, widget);
widget->pack_props_hash = g_hash_table_new (g_str_hash, g_str_equal);
/* update the quick reference hash table */
for (list = widget->packing_properties;
list && list->data;
list = list->next)
{
GladeProperty *property = list->data;
g_hash_table_insert (widget->pack_props_hash, property->klass->id, property);
}
/* Dont introspect on properties that are not parented yet.
*/
......
......@@ -74,7 +74,12 @@ struct _GladeWidget
* See also child_properties of
* GladeWidgetClass.
*/
GHashTable *props_hash; /* A Quick reference table to speed up calls to glade_widget_get_property()
*/
GHashTable *pack_props_hash; /* A Quick reference table to speed up calls to glade_widget_get_pack_property()
*/
GHashTable *signals; /* A table with a GPtrArray of GladeSignals (signal handlers),
* indexed by its name */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment