From bde9aabb1654330e6f36efb0b7bbbe8f646c1629 Mon Sep 17 00:00:00 2001 From: Juan Pablo Ugarte Date: Fri, 15 Nov 2013 22:45:17 -0300 Subject: Backport 2bc40ad87be072aac2759755df63707d43f8415c. Thanks to Thomas Martitz for the backport. Sort object dependancy before saving using a topological sorting algorithm _glade_tsort() instead of g_list_sort() with glade_widget_depends() which is not a transitive property. Closes Bug 709609 "[PATCH] Change way of sorting before writing XML output." Fixes Bug 711858 "editing glade project results in long CPU usage spikes after upgrading to 3.16 and GTK+3.10" This backport includes 1401a4bb43a3e56d642c34d5dc7d5ee86217cb3d which reverted part of 2bc40ad87be072aac2759755df63707d43f8415c. Conflicts: gladeui/Makefile.am gladeui/glade-project.c gladeui/glade-widget-adaptor.c gladeui/glade-widget.c plugins/gtk+/glade-gtk-entry.c plugins/gtk+/glade-gtk-size-group.c plugins/gtk+/glade-gtk-tree-view.c plugins/gtk+/glade-gtk-widget.c plugins/gtk+/gtk+.xml.in --- gladeui/Makefile.am | 3 + gladeui/glade-project.c | 365 +++++++++++++++++++++++++++++------------ gladeui/glade-property-class.c | 17 ++ gladeui/glade-property-class.h | 4 + gladeui/glade-property.c | 25 +++ gladeui/glade-property.h | 5 + gladeui/glade-tsort.c | 177 ++++++++++++++++++++ gladeui/glade-tsort.h | 51 ++++++ gladeui/glade-widget-adaptor.c | 37 ++--- gladeui/glade-widget-private.h | 36 ++++ gladeui/glade-widget.c | 33 +++- gladeui/glade-widget.h | 3 +- plugins/gtk+/glade-gtk.c | 32 ---- plugins/gtk+/gtk+.xml.in | 3 - 14 files changed, 627 insertions(+), 164 deletions(-) create mode 100644 gladeui/glade-tsort.c create mode 100644 gladeui/glade-tsort.h create mode 100644 gladeui/glade-widget-private.h diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am index 1e4e5b81..98ca9a65 100644 --- a/gladeui/Makefile.am +++ b/gladeui/Makefile.am @@ -56,6 +56,7 @@ libgladeui_1_la_SOURCES = \ glade-popup.h \ glade-marshallers.h \ glade-accumulators.h \ + glade-tsort.c \ glade-widget-action.c \ glade-name-context.c \ glade-displayable-values.c \ @@ -124,6 +125,8 @@ noinst_HEADERS = \ glade-object-stub.h \ glade-popup.h \ glade-accumulators.h + glade-tsort.h \ + glade-widget-private.h if PLATFORM_WIN32 libgladeui_1_la_LDFLAGS += -no-undefined diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c index 850e7bfa..e75d5025 100644 --- a/gladeui/glade-project.c +++ b/gladeui/glade-project.c @@ -51,6 +51,9 @@ #include "glade-name-context.h" #include "glade-object-stub.h" +#include "glade-widget-private.h" +#include "glade-tsort.h" + #define VALID_ITER(project, iter) ((iter)!= NULL && G_IS_OBJECT ((iter)->user_data) && ((GladeProject*)(project))->priv->stamp == (iter)->stamp) enum @@ -211,6 +214,8 @@ static void glade_project_verify_adaptor (GladeProject * gboolean forwidget, GladeSupportMask *mask); +static GladeXmlContext *glade_project_write (GladeProject *project); + static GladeWidget *search_ancestry_by_name (GladeWidget *toplevel, const gchar *name); @@ -1795,69 +1800,6 @@ glade_project_write_resource_path (GladeProject *project, } } -static gint -sort_project_dependancies (GObject *a, GObject *b) -{ - GladeWidget *ga, *gb; - - ga = glade_widget_get_from_gobject (a); - gb = glade_widget_get_from_gobject (b); - - if (glade_widget_adaptor_depends (ga->adaptor, ga, gb)) - return 1; - else if (glade_widget_adaptor_depends (gb->adaptor, gb, ga)) - return -1; - else - return strcmp (ga->name, gb->name); -} - -static GladeXmlContext * -glade_project_write (GladeProject *project) -{ - GladeXmlContext *context; - GladeXmlDoc *doc; - GladeXmlNode *root; /* *comment_node; */ - GList *list; - - doc = glade_xml_doc_new (); - context = glade_xml_context_new (doc, NULL); - root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT (project->priv->format)); - glade_xml_doc_set_root (doc, root); - - glade_project_update_comment (project); - /* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */ - - /* XXX Need to append this to the doc ! not the ROOT ! - glade_xml_node_append_child (root, comment_node); */ - - glade_project_write_required_libs (project, context, root); - - glade_project_write_naming_policy (project, context, root); - - glade_project_write_resource_path (project, context, root); - - /* Sort the whole thing */ - project->priv->objects = - g_list_sort (project->priv->objects, - (GCompareFunc)sort_project_dependancies); - - for (list = project->priv->objects; list; list = list->next) - { - GladeWidget *widget; - - widget = glade_widget_get_from_gobject (list->data); - - /* - * Append toplevel widgets. Each widget then takes - * care of appending its children. - */ - if (widget->parent == NULL) - glade_widget_write (widget, context, root); - } - - return context; -} - /** * glade_project_save: * @project: a #GladeProject @@ -2485,6 +2427,224 @@ glade_project_verify_adaptor (GladeProject *project, } + +static gint +glade_widgets_name_cmp (gconstpointer ga, gconstpointer gb) +{ + return g_strcmp0 (glade_widget_get_name ((gpointer)ga), glade_widget_get_name ((gpointer)gb)); +} + +static inline gboolean +glade_project_widget_hard_depends (GladeWidget *widget, GladeWidget *another) +{ + GList *l; + + for (l = _glade_widget_peek_prop_refs (another); l; l = g_list_next (l)) + { + GladePropertyClass *klass; + + /* If one of the properties that reference @another is + * owned by @widget then @widget depends on @another + */ + if (glade_property_get_widget (l->data) == widget && + (klass = glade_property_get_class (l->data)) && + glade_property_class_get_construct_only (klass)) + return TRUE; + } + + return FALSE; +} + +static _NodeEdge * +glade_project_get_graph_deps (GladeProject *project) +{ + GladeProjectPrivate *priv = project->priv; + GList *l, *objects = NULL; + _NodeEdge *edges = NULL; + + /* Create list of GladeWidgets */ + for (l = priv->objects; l; l = g_list_next (l)) + objects = g_list_prepend (objects, glade_widget_get_from_gobject (l->data)); + + /* Sort objects alphabetically */ + objects = g_list_sort (objects, glade_widgets_name_cmp); + + /* Create edges of the directed graph */ + for (l = objects; l; l = g_list_next (l)) + { + GladeWidget *predecessor = l->data; + GladeWidget *predecessor_top; + GList *ll; + + predecessor_top = glade_widget_get_toplevel (predecessor); + + for (ll = objects; ll; ll = g_list_next (ll)) + { + GladeWidget *successor = ll->data; + GladeWidget *successor_top; + + successor_top = glade_widget_get_toplevel (successor); + + /* Ignore object within the same toplevel */ + if (predecessor_top == successor_top) + continue; + + /* Check if succesor depends on predecessor and add a corresponding + * edge to the dependency graph. + * Note that we add the implicit dependency on their respective + * toplevels because that is what we care! + */ + if (glade_widget_depends (successor, predecessor)) + edges = _node_edge_prepend (edges, predecessor_top, successor_top); + } + } + + g_list_free (objects); + + return edges; +} + +static GList * +glade_project_get_nodes_from_edges (GladeProject *project, _NodeEdge *edges) +{ + _NodeEdge *edge, *hard_edges = NULL; + GList *cycles = NULL; + + /* Collect widgets with circular dependencies */ + for (edge = edges; edge; edge = edge->next) + { + if (glade_widget_get_parent (edge->successor) == edge->predecessor || + glade_project_widget_hard_depends (edge->predecessor, edge->successor)) + hard_edges = _node_edge_prepend (hard_edges, edge->predecessor, edge->successor); + + /* Just toplevels */ + if (glade_widget_get_parent (edge->successor)) + continue; + + if (!g_list_find (cycles, edge->successor)) + cycles = g_list_prepend (cycles, edge->successor); + } + + /* Sort them alphabetically */ + cycles = g_list_sort (cycles, glade_widgets_name_cmp); + + if (!hard_edges) + return cycles; + + /* Sort them by hard deps */ + cycles = _glade_tsort (&cycles, &hard_edges); + + if (hard_edges) + { + GList *hard_cycles = NULL; + + /* Collect widgets with hard circular dependencies */ + for (edge = hard_edges; edge; edge = edge->next) + { + /* Just toplevels */ + if (glade_widget_get_parent (edge->successor)) + continue; + + if (!g_list_find (hard_cycles, edge->successor)) + hard_cycles = g_list_prepend (hard_cycles, edge->successor); + } + + /* And append to the end of the cycles list */ + cycles = g_list_concat (cycles, g_list_sort (hard_cycles, glade_widgets_name_cmp)); + + /* Opps! there is at least one hard circular dependency, + * GtkBuilder will fail to set one of the properties that create the cycle + */ + + _node_edge_free (hard_edges); + } + + return cycles; +} + +static GList * +glade_project_get_ordered_toplevels (GladeProject *project) +{ + GladeProjectPrivate *priv = project->priv; + GList *l, *sorted_tree, *tree = NULL; + _NodeEdge *edges; + + /* Create list of toplevels GladeWidgets */ + for (l = priv->tree; l; l = g_list_next (l)) + tree = g_list_prepend (tree, glade_widget_get_from_gobject (l->data)); + + /* Sort toplevels alphabetically */ + tree = g_list_sort (tree, glade_widgets_name_cmp); + + edges = glade_project_get_graph_deps (project); + + /* Sort tree */ + sorted_tree = _glade_tsort (&tree, &edges); + + if (edges) + { + GList *cycles = glade_project_get_nodes_from_edges (project, edges); + + /* And append to the end of the sorted list */ + sorted_tree = g_list_concat (sorted_tree, cycles); + + _node_edge_free (edges); + } + + /* No need to free tree as tsort will consume the list */ + + return sorted_tree; +} + +static GladeXmlContext * +glade_project_write (GladeProject *project) +{ + GladeXmlContext *context; + GladeXmlDoc *doc; + GladeXmlNode *root; /* *comment_node; */ + GList *list; + GList *toplevels; + + doc = glade_xml_doc_new (); + context = glade_xml_context_new (doc, NULL); + root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT (project->priv->format)); + glade_xml_doc_set_root (doc, root); + + glade_project_update_comment (project); + /* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */ + + /* XXX Need to append this to the doc ! not the ROOT ! + glade_xml_node_append_child (root, comment_node); */ + + glade_project_write_required_libs (project, context, root); + + glade_project_write_naming_policy (project, context, root); + + glade_project_write_resource_path (project, context, root); + + /* Get sorted toplevels */ + toplevels = glade_project_get_ordered_toplevels (project); + + for (list = toplevels; list; list = g_list_next (list)) + { + GladeWidget *widget = list->data; + + /* + * Append toplevel widgets. Each widget then takes + * care of appending its children. + */ + if (!glade_widget_get_parent (widget)) + glade_widget_write (widget, context, root); + else + g_warning ("Tried to save a non toplevel object '%s' at xml root", + glade_widget_get_name (widget)); + } + + g_list_free (toplevels); + + return context; +} + /** * glade_project_verify_widget_adaptor: * @project: A #GladeProject @@ -2928,58 +3088,57 @@ glade_project_check_reordered (GladeProject *project, GladeWidget *parent, GList *old_order) { - GList *new_order, *l, *ll; - gint *order, n_children, i; - GtkTreeIter iter; - GtkTreePath *path; + GList *new_order, *l, *ll; + gint *order, n_children, i; + GtkTreeIter iter; + GtkTreePath *path; - g_return_if_fail (GLADE_IS_PROJECT (project)); - g_return_if_fail (GLADE_IS_WIDGET (parent)); - g_return_if_fail (glade_project_has_object (project, - glade_widget_get_object (parent))); + g_return_if_fail (GLADE_IS_PROJECT (project)); + g_return_if_fail (GLADE_IS_WIDGET (parent)); + g_return_if_fail (glade_project_has_object (project, + glade_widget_get_object (parent))); - new_order = glade_widget_get_children (parent); + new_order = glade_widget_get_children (parent); - /* Check if the list changed */ - for (l = old_order, ll = new_order; - l && ll; - l = l->next, ll = ll->next) - { - if (l->data != ll->data) - break; - } + /* Check if the list changed */ + for (l = old_order, ll = new_order; l && ll; l = l->next, ll = ll->next) + { + if (l->data != ll->data) + break; + } - if (l || ll) - { - n_children = glade_project_count_children (project, parent); - order = g_new (gint, n_children); + if (l || ll) + { + n_children = glade_project_count_children (project, parent); + order = g_new (gint, n_children); + + for (i = 0, l = new_order; l; l = l->next) + { + GObject *obj = l->data; - for (i = 0, l = new_order; l; l = l->next) - { - GObject *obj = l->data; + if (glade_project_has_object (project, obj)) + { + GList *node = g_list_find (old_order, obj); - if (glade_project_has_object (project, obj)) - { - GList *node = g_list_find (old_order, obj); + g_assert (node); - g_assert (node); + order[i] = g_list_position (old_order, node); - order[i] = g_list_position (old_order, node); + i++; + } + } - i++; - } - } + /* Signal that the rows were reordered */ + glade_project_model_get_iter_for_object (project, glade_widget_get_object (parent), &iter); + path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project), path, &iter, order); + gtk_tree_path_free (path); - /* Signal that the rows were reordered */ - glade_project_model_get_iter_for_object (project, glade_widget_get_object (parent), &iter); - path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter); - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project), path, &iter, order); - gtk_tree_path_free (path); + g_free (order); - g_free (order); - } + } - g_list_free (new_order); + g_list_free (new_order); } /** diff --git a/gladeui/glade-property-class.c b/gladeui/glade-property-class.c index 6a66716a..9c9dc18b 100644 --- a/gladeui/glade-property-class.c +++ b/gladeui/glade-property-class.c @@ -1762,3 +1762,20 @@ glade_property_class_compare (GladePropertyClass *klass, return retval; } + +void +glade_property_class_set_construct_only (GladePropertyClass *property_class, + gboolean construct_only) +{ + g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class)); + + property_class->construct_only = construct_only; +} + +gboolean +glade_property_class_get_construct_only (GladePropertyClass *property_class) +{ + g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE); + + return property_class->construct_only; +} diff --git a/gladeui/glade-property-class.h b/gladeui/glade-property-class.h index b2ec3efc..cdfcbc2c 100644 --- a/gladeui/glade-property-class.h +++ b/gladeui/glade-property-class.h @@ -278,6 +278,10 @@ gint glade_property_class_compare (GladePropertyC const GValue *value2, GladeProjectFormat fmt); +void glade_property_class_set_construct_only (GladePropertyClass *property_class, + gboolean construct_only); +gboolean glade_property_class_get_construct_only (GladePropertyClass *property_class); + G_END_DECLS #endif /* __GLADE_PROPERTY_CLASS_H__ */ diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c index 88009c38..0043b75a 100644 --- a/gladeui/glade-property.c +++ b/gladeui/glade-property.c @@ -1465,6 +1465,31 @@ glade_property_get_enabled (GladeProperty *property) return property->enabled; } +GladePropertyClass * +glade_property_get_class (GladeProperty *property) +{ + g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL); + + return property->klass; +} + +void +glade_property_set_widget (GladeProperty *property, + GladeWidget *widget) +{ + g_return_if_fail (GLADE_IS_PROPERTY (property)); + + property->widget = widget; +} + +GladeWidget * +glade_property_get_widget (GladeProperty *property) +{ + g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL); + + return property->widget; +} + static gint glade_property_su_stack = 0; diff --git a/gladeui/glade-property.h b/gladeui/glade-property.h index f8fd63d3..66768ff8 100644 --- a/gladeui/glade-property.h +++ b/gladeui/glade-property.h @@ -191,6 +191,11 @@ void glade_property_set_enabled (GladeProperty gboolean glade_property_get_enabled (GladeProperty *property); +GladePropertyClass *glade_property_get_class (GladeProperty *property); + +GladeWidget *glade_property_get_widget (GladeProperty *property); +void glade_property_set_widget (GladeProperty *property, + GladeWidget *widget); void glade_property_i18n_set_comment (GladeProperty *property, const gchar *str); diff --git a/gladeui/glade-tsort.c b/gladeui/glade-tsort.c new file mode 100644 index 00000000..439da33e --- /dev/null +++ b/gladeui/glade-tsort.c @@ -0,0 +1,177 @@ +/* + * glade-tsort.c: a topological sorting algorithm implementation + * + * Copyright (C) 2013 Juan Pablo Ugarte. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte + */ + +#include "glade-tsort.h" + +/** + * _node_edge_prepend: + * @node: a _NodeEdge pointer or NULL + * @predecessor: + * @successor: + * + * Adds a new node with the values @predecessor and @successor to the start of + * @node list. + * + * Returns: the new start of the node list. + */ +_NodeEdge * +_node_edge_prepend (_NodeEdge *node, + gpointer predecessor, + gpointer successor) +{ + _NodeEdge *edge = g_slice_new (_NodeEdge); + + edge->predecessor = predecessor; + edge->successor = successor; + edge->next = node; + + return edge; +} + +void +_node_edge_free (_NodeEdge *node) +{ + g_slice_free_chain (_NodeEdge, node, next); +} + +static inline void +tsort_remove_non_start_nodes (GList **nodes, _NodeEdge *edges) +{ + _NodeEdge *edge; + + for (edge = edges; edge; edge = edge->next) + *nodes = g_list_remove (*nodes, edge->successor); +} + + +static inline gboolean +tsort_node_has_no_incoming_edge (gpointer node, _NodeEdge *edges) +{ + _NodeEdge *edge; + + for (edge = edges; edge; edge = edge->next) + { + if (node == edge->successor) + return FALSE; + } + + return TRUE; +} + +/** + * _glade_tsort: + * @nodes: list of pointers to sort + * @edges: pointer to the list of #_NodeEdge that conform the dependency + * graph of @nodes. + * + * Topological sorting implementation. + * After calling this funtion only graph cycles (circular dependencies) are left + * in @edges list. So if @edges is NULL it means the returned list has all the + * elements topologically sorted if not it means there are at least one + * circular dependency. + * + * L ← Empty list that will contain the sorted elements + * S ← Set of all nodes with no incoming edges + * while S is non-empty do + * remove a node n from S + * insert n into L + * for each node m with an edge e from n to m do + * remove edge e from the graph + * if m has no other incoming edges then + * insert m into S + * return L (a topologically sorted order if graph has no edges) + * + * see: http://en.wikipedia.org/wiki/Topological_sorting + * + * Returns: a new list sorted by dependency including nodes only present in @edges + */ +GList * +_glade_tsort (GList **nodes, _NodeEdge **edges) +{ + GList *sorted_nodes; + + /* L ← Empty list that will contain the sorted elements */ + sorted_nodes = NULL; + + /* S ← Set of all nodes with no incoming edges */ + tsort_remove_non_start_nodes (nodes, *edges); + + /* while S is non-empty do */ + while (*nodes) + { + _NodeEdge *edge, *next, *prev = NULL; + gpointer n; + + /* remove a node n from S */ + n = (*nodes)->data; + *nodes = g_list_delete_link (*nodes, *nodes); + + /* insert n into L */ + /*if (!glade_widget_get_parent (n)) this would be a specific optimization */ + sorted_nodes = g_list_prepend (sorted_nodes, n); + + /* for each node m ... */ + for (edge = *edges; edge; edge = next) + { + next = edge->next; + + /* ... with an edge e from n to m do */ + if (edge->predecessor == n) + { + /* remove edge e from the graph */ + if (prev) + prev->next = (prev->next) ? prev->next->next : NULL; + else + /* edge is the first element in the list so we only need to + * change the start of the list */ + *edges = next; + + /* if m has no other incoming edges then */ + if (tsort_node_has_no_incoming_edge (edge->successor, *edges)) + /* insert m into S */ + *nodes = g_list_prepend (*nodes, edge->successor); + + g_slice_free (_NodeEdge, edge); + } + else + /* Keep a pointer to the previous node in the iteration to make + * things easier when removing a node + */ + prev = edge; + } + } + + /* if graph has edges then return error (graph has at least one cycle) */ +#if 0 /* We rather not return NULL, caller must check if edge */ + if (*edges) + { + g_list_free (sorted_nodes); + g_slice_free_chain (_NodeEdge, *edges, next); + *edges = NULL; + return NULL; + } +#endif + + /* return L (a topologically sorted order if edge is NULL) */ + return g_list_reverse (sorted_nodes); +} diff --git a/gladeui/glade-tsort.h b/gladeui/glade-tsort.h new file mode 100644 index 00000000..3026e2d5 --- /dev/null +++ b/gladeui/glade-tsort.h @@ -0,0 +1,51 @@ +/* + * glade-tsort.h: a topological sorting algorithm implementation + * + * Copyright (C) 2013 Juan Pablo Ugarte. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: + * Juan Pablo Ugarte + */ + +#ifndef __GLADE_TSORT_H__ +#define __GLADE_TSORT_H__ + +#include + +G_BEGIN_DECLS + +typedef struct __NodeEdge _NodeEdge; + +struct __NodeEdge +{ + gpointer predecessor; + gpointer successor; + _NodeEdge *next; +}; + +_NodeEdge *_node_edge_prepend (_NodeEdge *node, + gpointer predecessor, + gpointer successor); + +void _node_edge_free (_NodeEdge *node); + +GList *_glade_tsort (GList **nodes, + _NodeEdge **edges); + +G_END_DECLS + +#endif /* __GLADE_TSORT_H__ */ diff --git a/gladeui/glade-widget-adaptor.c b/gladeui/glade-widget-adaptor.c index 6777e183..0f9c2e47 100644 --- a/gladeui/glade-widget-adaptor.c +++ b/gladeui/glade-widget-adaptor.c @@ -42,6 +42,7 @@ #include "glade-accumulators.h" #include "glade-displayable-values.h" #include "glade-editor-table.h" +#include "glade-widget-private.h" /* For g_file_exists */ #include @@ -859,32 +860,21 @@ glade_widget_adaptor_object_child_action_activate (GladeWidgetAdaptor *adaptor, static gboolean glade_widget_adaptor_object_depends (GladeWidgetAdaptor *adaptor, - GladeWidget *widget, - GladeWidget *another) + GladeWidget *widget, + GladeWidget *another) { - gboolean depends = FALSE; - GList *l; + GList *l; - for (l = another->prop_refs; !depends && l; l = l->next) - { - GladeProperty *property = l->data; - GladeWidget *prop_widget = property->widget; - - /* If one of the properties that reference @another is - * owned by @widget then @widget depends on @another - */ - if (prop_widget == widget) - depends = TRUE; + for (l = _glade_widget_peek_prop_refs (another); l; l = g_list_next (l)) + { + /* If one of the properties that reference @another is + * owned by @widget then @widget depends on @another + */ + if (glade_property_get_widget (l->data) == widget) + return TRUE; + } - /* Or if the widget that owns a property which references - * @another is somewhere inside @widget... then @widget - * also depends on @another. - */ - else if (glade_widget_is_ancestor (prop_widget, widget)) - depends = TRUE; - } - - return depends; + return FALSE; } static void @@ -3724,4 +3714,3 @@ glade_widget_adaptor_create_editable (GladeWidgetAdaptor *adaptor, return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_editable (adaptor, type); } - diff --git a/gladeui/glade-widget-private.h b/gladeui/glade-widget-private.h new file mode 100644 index 00000000..12869f47 --- /dev/null +++ b/gladeui/glade-widget-private.h @@ -0,0 +1,36 @@ +/* + * glade-widget-private.h + * + * Copyright (C) 2013 Juan Pablo Ugarte + * + * Authors: + * Juan Pablo Ugarte + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GLADE_WIDGET_PRIVATE_H__ +#define __GLADE_WIDGET_PRIVATE_H__ + +#include "glade-widget.h" + +G_BEGIN_DECLS + +GList *_glade_widget_peek_prop_refs (GladeWidget *widget); + +G_END_DECLS + +#endif /* __GLADE_WIDGET_PRIVATE_H__ */ diff --git a/gladeui/glade-widget.c b/gladeui/glade-widget.c index d8045bef..f7ee5866 100644 --- a/gladeui/glade-widget.c +++ b/gladeui/glade-widget.c @@ -45,7 +45,7 @@ #include "glade-accumulators.h" #include "glade-project.h" #include "glade-widget-adaptor.h" -#include "glade-widget.h" +#include "glade-widget-private.h" #include "glade-marshallers.h" #include "glade-property.h" #include "glade-property-class.h" @@ -1920,6 +1920,14 @@ glade_widget_create_packing_properties (GladeWidget *container, GladeWidget *wid return g_list_reverse (packing_props); } +/* Private API */ + +GList * +_glade_widget_peek_prop_refs (GladeWidget *widget) +{ + return widget->prop_refs; +} + /******************************************************************************* API *******************************************************************************/ @@ -4105,6 +4113,29 @@ glade_widget_is_ancestor (GladeWidget *widget, return FALSE; } +/** + * glade_widget_depends: + * @widget: a #GladeWidget + * @other: another #GladeWidget + * + * Determines whether @widget is somehow dependent on @other, in + * which case it should be serialized after @other. + * + * A widget is dependent on another widget. + * It does not take into account for children dependencies. + * + * Return value: %TRUE if @widget depends on @other. + **/ +gboolean +glade_widget_depends (GladeWidget *widget, + GladeWidget *other) +{ + g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (GLADE_IS_WIDGET (other), FALSE); + + return glade_widget_adaptor_depends (widget->adaptor, widget, other); +} + static gint glade_widget_su_stack = 0; diff --git a/gladeui/glade-widget.h b/gladeui/glade-widget.h index 95d86015..348edc8d 100644 --- a/gladeui/glade-widget.h +++ b/gladeui/glade-widget.h @@ -98,7 +98,6 @@ struct _GladeWidget */ GList *locked_widgets; /* A list of widgets this widget has locked down. */ - /* Construct parameters: */ GladeWidget *construct_template; GladeCreateReason construct_reason; @@ -279,6 +278,8 @@ gchar *glade_widget_generate_path_name (GladeWidget *w gboolean glade_widget_is_ancestor (GladeWidget *widget, GladeWidget *ancestor); +gboolean glade_widget_depends (GladeWidget *widget, + GladeWidget *other); /******************************************************************************* Project, object property references diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c index c784341f..d797467b 100644 --- a/plugins/gtk+/glade-gtk.c +++ b/plugins/gtk+/glade-gtk.c @@ -4804,17 +4804,6 @@ glade_gtk_expander_write_child (GladeWidgetAdaptor *adaptor, /* -------------------------------- GtkEntry -------------------------------- */ -gboolean -glade_gtk_entry_depends (GladeWidgetAdaptor *adaptor, - GladeWidget *widget, - GladeWidget *another) -{ - if (GTK_IS_ENTRY_BUFFER (another->object)) - return TRUE; - - return GWA_GET_CLASS (GTK_TYPE_WIDGET)->depends (adaptor, widget, another); -} - static void glade_gtk_entry_changed (GtkEditable *editable, GladeWidget *gentry) @@ -10072,16 +10061,6 @@ glade_gtk_radio_button_set_property (GladeWidgetAdaptor *adaptor, } /*--------------------------- GtkSizeGroup ---------------------------------*/ -gboolean -glade_gtk_size_group_depends (GladeWidgetAdaptor *adaptor, - GladeWidget *widget, - GladeWidget *another) -{ - if (GTK_IS_WIDGET (another->object)) - return TRUE; - - return GWA_GET_CLASS (G_TYPE_OBJECT)->depends (adaptor, widget, another); -} #define GLADE_TAG_SIZEGROUP_WIDGETS "widgets" #define GLADE_TAG_SIZEGROUP_WIDGET "widget" @@ -12270,17 +12249,6 @@ glade_gtk_treeview_remove_child (GladeWidgetAdaptor *adaptor, gtk_tree_view_remove_column (view, column); } -gboolean -glade_gtk_treeview_depends (GladeWidgetAdaptor *adaptor, - GladeWidget *widget, - GladeWidget *another) -{ - if (GTK_IS_TREE_MODEL (another->object)) - return TRUE; - - return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->depends (adaptor, widget, another); -} - /*--------------------------- GtkAdjustment ---------------------------------*/ void glade_gtk_adjustment_write_widget (GladeWidgetAdaptor *adaptor, diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in index f5719f9a..56482f00 100644 --- a/plugins/gtk+/gtk+.xml.in +++ b/plugins/gtk+/gtk+.xml.in @@ -859,7 +859,6 @@ embedded in another object glade_gtk_entry_create_editable glade_gtk_entry_set_property glade_gtk_entry_read_widget - glade_gtk_entry_depends @@ -2017,7 +2016,6 @@ embedded in another object - glade_gtk_size_group_depends glade_gtk_size_group_read_widget glade_gtk_size_group_write_widget glade_gtk_size_group_set_property @@ -2203,7 +2201,6 @@ embedded in another object glade_gtk_treeview_add_child glade_gtk_treeview_remove_child glade_gtk_treeview_action_activate - glade_gtk_treeview_depends -- cgit v1.2.1