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



--=-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--





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