[Glade-devel] [glade3, patch] handling internal children

Paolo Borelli pborelli@katamail.com
Fri, 24 Oct 2003 17:41:24 +0200


--=-lUV/E+zT/MZdxfe5/Q8q
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hi!

In the last days (actually nights ;) ) I've worked on handling internal
children in glade3.

Fixing this issue is IMHO pretty important because it affects the
GtkDialog widget and consequently a good part of the .glade files in
Gnome.
As a matter of fact after the below patch I've been able to open a
couple of random glade files from my gnome sources... you still get some
warnings for unimplented things as properties of type FLAGS, but the
project is opened :)

Since those were simpler, I've already committed to cvs the patches
which allow the creation of internal children when a widget is created
from the palette and that write the internal-child attribute when saving
the .glade file; the last step is handling the internal-child attribute
when reading from xml and it is implemented in the attached patch: since
this is the more intrusive patch I thought it was a good idea to pass it
by the list for review before committing.

Note: I only fixed internal children of GtkDialog (i.e. dialog->vbox and
dialog->action_area) but the infrastructure should work also for other
widgets which have internal children. I would really welcome suggestions
(or even better patches) of other widgets that need to handle the
internal-child attribute).



Patch explanation:

[In the patches already in cvs I made sure that when a widget which has
internal children is created also the GladeWidgets associated with
internal children are created; GladeWidegets of internal child have a
->internal member which contains the name of the internal child, e.g.
"vbox"]

In the patch below I move the creation on these GladeWidgets from
fill_empty() to post_create() since this method is executed also when
the widget is created from a .glade file.
When an internal-child is found, we don't have to create the
corresponding GtkWidget, but only the GladeWidget: to do so I factored
out glade_widget_fill_widget_from_node from glade_widget_new_from_node.
To retrieve the actual GtkWidget we must walk up the hierarchy until we
find a parent that can give us the requested internal child via the
class->get_internal_child method.
The method is as usual specified in the catalog xml file.


ciao
	paolo

--=-lUV/E+zT/MZdxfe5/Q8q
Content-Disposition: attachment; filename=read_int_child.patch
Content-Type: text/x-patch; name=read_int_child.patch; charset=
Content-Transfer-Encoding: 7bit

? autom4te.cache
? glade-3.desktop
? temp.patch
? src/glade-3
Index: src/glade-gtk.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-gtk.c,v
retrieving revision 1.35
diff -u -p -r1.35 glade-gtk.c
--- src/glade-gtk.c	23 Oct 2003 17:40:27 -0000	1.35
+++ src/glade-gtk.c	24 Oct 2003 14:12:27 -0000
@@ -524,7 +524,7 @@ ignore (GObject *object, GValue *value)
 
 /* ------------------------------------ Post Create functions ------------------------------ */
 void
-glade_gtk_window_post_create (GObject *object, GValue *not_used)
+glade_gtk_window_post_create (GObject *object)
 {
 	GtkWindow *window = GTK_WINDOW (object);
 
@@ -534,17 +534,45 @@ glade_gtk_window_post_create (GObject *o
 }
 
 void
-glade_gtk_dialog_post_create (GObject *object, GValue *not_used)
+glade_gtk_dialog_post_create (GObject *object)
 {
 	GtkDialog *dialog = GTK_DIALOG (object);
+	GladeWidget *widget;
+	GladeWidget *vbox_widget;
+	GladeWidget *actionarea_widget;
+	GladeWidgetClass *child_class;
 
 	g_return_if_fail (GTK_IS_DIALOG (dialog));
 
+	widget = glade_widget_get_from_gtk_widget (GTK_WIDGET (dialog));
+	if (!widget)
+		return;
+
+	/* create the GladeWidgets for internal childrens */
+	child_class = glade_widget_class_get_by_name ("GtkVBox");
+	if (!child_class)
+		return;
+
+	vbox_widget = glade_widget_new_for_internal_child (child_class, widget,
+							   dialog->vbox, "vbox");
+	if (!vbox_widget)
+		return;
+
+	child_class = glade_widget_class_get_by_name ("GtkHButtonBox");
+	if (!child_class)
+		return;
+
+	actionarea_widget = glade_widget_new_for_internal_child (child_class, vbox_widget,
+								 dialog->action_area, "action_area");
+	if (!actionarea_widget)
+		return;
+
+	/* set a reasonable default size for a dialog */
 	gtk_window_set_default_size (GTK_WINDOW (dialog), 320, 260);
 }
 
 void
-glade_gtk_message_dialog_post_create (GObject *object, GValue *not_used)
+glade_gtk_message_dialog_post_create (GObject *object)
 {
 	GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
 
@@ -554,7 +582,7 @@ glade_gtk_message_dialog_post_create (GO
 }
 
 void
-glade_gtk_check_button_post_create (GObject *object, GValue *not_used)
+glade_gtk_check_button_post_create (GObject *object)
 {
 	GtkCheckButton *button = GTK_CHECK_BUTTON (object);
 	GtkWidget *label;
@@ -569,7 +597,7 @@ glade_gtk_check_button_post_create (GObj
 }
 
 void
-glade_gtk_table_post_create (GObject *object, GValue *value)
+glade_gtk_table_post_create (GObject *object)
 {
 	GtkTable *table = GTK_TABLE (object);
 	GList *list;
@@ -698,42 +726,11 @@ glade_gtk_container_fill_empty (GObject 
 void
 glade_gtk_dialog_fill_empty (GObject *dialog)
 {
-	GtkWidget *vbox;
-	GtkWidget *action_area;
-	GladeWidget *widget;
-	GladeWidget *vbox_widget;
-	GladeWidget *actionarea_widget;
-	GladeWidgetClass *child_class;
-
 	g_return_if_fail (GTK_IS_DIALOG (dialog));
 
-	widget = glade_widget_get_from_gtk_widget (GTK_WIDGET (dialog));
-	if (!widget)
-		return;
-
-	/* create the GladeWidgets for internal childrens */
-	vbox = GTK_DIALOG (dialog)->vbox;
-	child_class = glade_widget_class_get_by_name ("GtkVBox");
-	if (!child_class)
-		return;
-
-	vbox_widget = glade_widget_new_for_internal_child (child_class, widget,
-							   vbox, "vbox");
-	if (!vbox_widget)
-		return;
-
-	action_area = GTK_DIALOG (dialog)->action_area;
-	child_class = glade_widget_class_get_by_name ("GtkHButtonBox");
-	if (!child_class)
-		return;
-
-	actionarea_widget = glade_widget_new_for_internal_child (child_class, vbox_widget,
-								 action_area, "action_area");
-	if (!actionarea_widget)
-		return;
-
 	/* add a placeholder in the vbox */
-	gtk_box_pack_start_defaults (GTK_BOX (vbox), glade_placeholder_new ());
+	gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+				     glade_placeholder_new ());
 }
 
 void
@@ -745,4 +742,23 @@ glade_gtk_paned_fill_empty (GObject *pan
 	gtk_paned_add2 (GTK_PANED (paned), glade_placeholder_new ());
 }
 
+/* -------------------------------- Get Internal Child functions --------------------------- */
+void
+glade_gtk_dialog_get_internal_child (GtkWidget *dialog,
+				     const gchar *name,
+				     GtkWidget **child)
+{
+	GtkWidget *child_widget;
+
+	g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+	if (strcmp ("vbox", name) == 0)
+		child_widget = GTK_DIALOG (dialog)->vbox;
+	else if (strcmp ("action_area", name) == 0)
+		child_widget = GTK_DIALOG (dialog)->action_area;
+	else
+		child_widget = NULL;
+
+	*child = child_widget;
+}
 
Index: src/glade-widget-class.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget-class.c,v
retrieving revision 1.44
diff -u -p -r1.44 glade-widget-class.c
--- src/glade-widget-class.c	15 Oct 2003 21:48:40 -0000	1.44
+++ src/glade-widget-class.c	24 Oct 2003 14:12:29 -0000
@@ -347,6 +347,7 @@ glade_widget_class_extend_with_file (Gla
 	char *replace_child_function_name;
 	char *post_create_function_name;
 	char *fill_empty_function_name;
+	char *get_internal_child_function_name;
 
 	g_return_val_if_fail (filename != NULL, FALSE);
 
@@ -379,6 +380,13 @@ glade_widget_class_extend_with_file (Gla
 			g_warning ("Could not find %s\n", fill_empty_function_name);
 	}
 	g_free (fill_empty_function_name);
+
+	get_internal_child_function_name = glade_xml_get_value_string (node, GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION);
+	if (get_internal_child_function_name && widget_class->module) {
+		if (!g_module_symbol (widget_class->module, get_internal_child_function_name, (void **) &widget_class->get_internal_child))
+			g_warning ("Could not find %s\n", get_internal_child_function_name);
+	}
+	g_free (get_internal_child_function_name);
 
 	/* if we found a <properties> tag on the xml file, we add the properties
 	 * that we read from the xml file to the class.
Index: src/glade-widget-class.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget-class.h,v
retrieving revision 1.26
diff -u -p -r1.26 glade-widget-class.h
--- src/glade-widget-class.h	23 Oct 2003 17:40:27 -0000	1.26
+++ src/glade-widget-class.h	24 Oct 2003 14:12:29 -0000
@@ -83,16 +83,22 @@ struct _GladeWidgetClass
 			       GtkWidget *new,
 			       GtkWidget *container);
 
-	/* Executed after widget creation: e.g. sets the size of a window to a 
-	 * sane default.
+	/* Executed after widget creation: takes care of creating the GladeWidgets
+	 * associated with internal children. It also the place to set sane defaults,
+	 * e.g. set the size of a window.
 	 */
 	void (*post_create_function) (GObject *gobject);
 
 	/* If the widget is a container, this method takes care of adding the
-	 * needed placeholders. If the widget has internal children, this method
-	 * must create the associated GladeWidgets.
+	 * needed placeholders.
 	 */
 	void (*fill_empty) (GtkWidget *widget);
+
+	/* Retrieves the the internal child of the given name.
+	 */
+	void (*get_internal_child) (GtkWidget *parent,
+				    const gchar *name,
+				    GtkWidget **child);
 };
 
 
Index: src/glade-widget.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget.c,v
retrieving revision 1.81
diff -u -p -r1.81 glade-widget.c
--- src/glade-widget.c	23 Oct 2003 18:45:32 -0000	1.81
+++ src/glade-widget.c	24 Oct 2003 14:12:32 -0000
@@ -604,13 +604,6 @@ glade_widget_create_gtk_widget (GladeWid
 	 * Cuenca
 	 */
 
-	/* We need to call the post_create_function after the embed of the widget in
-	 * its parent.  Otherwise, calls to gtk_widget_grab_focus et al. will fail
-	 */
-	if (class->post_create_function) {
-		class->post_create_function (G_OBJECT (widget));
-	}
-
 	return widget;
 }
 
@@ -687,6 +680,11 @@ glade_widget_new_full (GladeWidgetClass 
 
 	glade_widget_associate_with_gtk_widget (widget, gtk_widget);
 
+	/* associate internal children and set sane defaults */
+	if (class->post_create_function) {
+		class->post_create_function (G_OBJECT (gtk_widget));
+	}
+
 	return widget;
 }
 
@@ -1349,37 +1347,25 @@ glade_widget_new_child_from_node (GladeX
 				  GladeProject *project,
 				  GladeWidget *parent);
 
-static GladeWidget *
-glade_widget_new_from_node_real (GladeXmlNode *node,
-				 GladeProject *project,
-				 GladeWidget *parent)
+static void
+glade_widget_fill_from_node (GladeXmlNode *node, GladeWidget *widget)
 {
-	GladeWidgetClass *class;
 	GladeXmlNode *child;
-	GladeWidget *widget;
-	GladeSignal *signal;
 	const gchar *class_name;
 	const gchar *widget_name;
 
+	g_return_if_fail (GLADE_IS_WIDGET (widget));
+
 	if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
-		return NULL;
+		return;
 
 	class_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_CLASS, NULL);
 	widget_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_ID, NULL);
 	if (!class_name || !widget_name)
-		return NULL;
-
-	class = glade_widget_class_get_by_name (class_name);
-	if (!class)
-		return NULL;
-
-	widget = glade_widget_new_full (class, project);
-	if (!widget)
-		return NULL;
+		return;
 
+	g_assert (strcmp (class_name, widget->class->name) == 0);
 	glade_widget_set_name (widget, widget_name);
-	if (parent)
-		glade_widget_set_packing_properties (widget, parent->class);
 
 	/* Children */
 	child =	glade_xml_node_get_children (node);
@@ -1387,7 +1373,7 @@ glade_widget_new_from_node_real (GladeXm
 		if (!glade_xml_node_verify_silent (child, GLADE_XML_TAG_CHILD))
 			continue;
 
-		if (!glade_widget_new_child_from_node (child, project, widget)) {
+		if (!glade_widget_new_child_from_node (child, widget->project, widget)) {
 			g_warning ("Failed to read child");
 			continue;
 		}
@@ -1396,6 +1382,8 @@ glade_widget_new_from_node_real (GladeXm
 	/* Signals */
 	child =	glade_xml_node_get_children (node);
 	for (; child; child = glade_xml_node_next (child)) {
+		GladeSignal *signal;
+
 		if (!glade_xml_node_verify_silent (child, GLADE_XML_TAG_SIGNAL))
 			continue;
 
@@ -1418,12 +1406,69 @@ glade_widget_new_from_node_real (GladeXm
 			continue;
 		}
 	}
+}
+
+GladeWidget *
+glade_widget_new_from_node_real (GladeXmlNode *node,
+				 GladeProject *project,
+				 GladeWidget *parent)
+{
+	GladeWidgetClass *class;
+	GladeWidget *widget;
+	const gchar *class_name;
+
+	if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
+		return NULL;
+
+	class_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_CLASS, NULL);
+	if (!class_name)
+		return NULL;
+
+	class = glade_widget_class_get_by_name (class_name);
+	if (!class)
+		return NULL;
+
+	widget = glade_widget_new_full (class, project);
+	if (!widget)
+		return NULL;
+
+	if (parent)
+		glade_widget_set_packing_properties (widget, parent->class);
+
+	glade_widget_fill_from_node (node, widget);
 
 	gtk_widget_show_all (widget->widget);
 
 	return widget;
 }
 
+/**
+ * When looking for an internal child we have to walk up the hierarchy...
+ */
+static GladeWidget *
+glade_widget_get_internal_child (GladeWidget *parent,
+				 const gchar *internal)
+{
+	GladeWidget *ancestor;
+	GladeWidget *child = NULL;
+
+	ancestor = parent;
+	while (ancestor) {
+		if (ancestor->class->get_internal_child) {
+			GtkWidget *widget;
+			ancestor->class->get_internal_child (ancestor->widget, internal, &widget);
+			if (widget) {
+				child = glade_widget_get_from_gtk_widget (widget);
+				if (child)
+					break;
+			}
+		}
+		ancestor = glade_widget_get_parent (ancestor);
+	}
+
+	return child;
+}
+
 static gboolean
 glade_widget_new_child_from_node (GladeXmlNode *node,
 				  GladeProject *project,
@@ -1437,14 +1482,6 @@ glade_widget_new_child_from_node (GladeX
 	if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
 		return FALSE;
 
-	/* we don't support internal children yet... */
-	internalchild = glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);
-	if (internalchild) {
-		g_warning ("Internal Child not supported yet");
-		g_free (internalchild);
-		return FALSE;
-	}
-
 	/* is it a placeholder? */
 	child_node = glade_xml_search_child (node, GLADE_XML_TAG_PLACEHOLDER);
 	if (child_node) {
@@ -1452,21 +1489,32 @@ glade_widget_new_child_from_node (GladeX
 		return TRUE;
 	}
 
-	/* Get and create the widget */
+	/* then it must be a widget */
 	child_node = glade_xml_search_child_required (node, GLADE_XML_TAG_WIDGET);
 	if (!child_node)
 		return FALSE;
 
-	child = glade_widget_new_from_node_real (child_node, project, parent);
-	if (!child)
-		/*
-		 * not enough memory... and now, how can I signal it
-		 * and not make the caller believe that it was a parsing
-		 * problem?
-		 */
-		return FALSE;
+	/* is it an internal child? */
+	internalchild = glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);
+	if (internalchild) {
+		child = glade_widget_get_internal_child (parent, internalchild);
+		if (!child) {
+			g_warning ("Failed to get internal child %s", internalchild);
+			g_free (internalchild);
+			return FALSE;
+		}
+		glade_widget_fill_from_node (child_node, child);
+	} else {
+		child = glade_widget_new_from_node_real (child_node, project, parent);
+		if (!child)
+			/* not enough memory... and now, how can I signal it
+			 * and not make the caller believe that it was a parsing
+			 * problem?
+			 */
+			return FALSE;
 
-	gtk_container_add (GTK_CONTAINER (parent->widget), child->widget);
+		gtk_container_add (GTK_CONTAINER (parent->widget), child->widget);
+	}
 
 	/* Get the packing properties */
 	child_node = glade_xml_search_child (node, GLADE_XML_TAG_PACKING);
@@ -1486,7 +1534,6 @@ glade_widget_new_child_from_node (GladeX
 			/* the tag should have the form <property name="...id...">...value...</property>*/
 			id = glade_xml_get_property_string_required (child_properties, GLADE_XML_TAG_NAME, NULL);
 			value = glade_xml_get_content (child_properties);
-
 			if (!value || !id) {
 				g_warning ("Invalid property %s:%s\n", value, id);
 				g_free (value);
@@ -1496,8 +1543,7 @@ glade_widget_new_child_from_node (GladeX
 
 			glade_util_replace (id, '_', '-');
 			property = glade_property_get_from_id (child->packing_properties, id);
-
-			if (property == NULL) {
+			if (!property) {
 				g_warning ("Could not apply property from node. Id :%s\n",
 					   id);
 				continue;
Index: src/glade.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade.h,v
retrieving revision 1.29
diff -u -p -r1.29 glade.h
--- src/glade.h	20 Oct 2003 18:16:33 -0000	1.29
+++ src/glade.h	24 Oct 2003 14:12:32 -0000
@@ -93,6 +93,7 @@
 #define GLADE_TAG_REPLACE_CHILD_FUNCTION "ReplaceChildFunction"
 #define GLADE_TAG_POST_CREATE_FUNCTION "PostCreateFunction"
 #define GLADE_TAG_FILL_EMPTY_FUNCTION "FillEmptyFunction"
+#define GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION "GetInternalChildFunction"
 #define GLADE_TAG_IN_PALETTE   "InPalette"
 
 #define GLADE_TAG_CATALOG      "GladeCatalog"
Index: widgets/gtkdialog.xml
===================================================================
RCS file: /cvs/gnome/glade3/widgets/gtkdialog.xml,v
retrieving revision 1.5
diff -u -p -r1.5 gtkdialog.xml
--- widgets/gtkdialog.xml	13 Oct 2003 16:15:22 -0000	1.5
+++ widgets/gtkdialog.xml	24 Oct 2003 14:12:32 -0000
@@ -2,6 +2,7 @@
 
   <PostCreateFunction>glade_gtk_dialog_post_create</PostCreateFunction>
   <FillEmptyFunction>glade_gtk_dialog_fill_empty</FillEmptyFunction>
+  <GetInternalChildFunction>glade_gtk_dialog_get_internal_child</GetInternalChildFunction>
 
   <Properties>
 

--=-lUV/E+zT/MZdxfe5/Q8q--