diff options
author | Jean Felder <jfelder@src.gnome.org> | 2020-03-19 22:20:37 +0100 |
---|---|---|
committer | Jean Felder <jfelder@src.gnome.org> | 2020-04-17 01:52:33 +0200 |
commit | b5013bf7e127a87cf9f1ab0aef048bf8ef9f46c5 (patch) | |
tree | 93712b6f1288fa5366c0a2e08311dcff7915fa76 | |
parent | ad9cfa67df13821c50a5499ed4c1a40dc4b29bb0 (diff) | |
download | pygobject-b5013bf7e127a87cf9f1ab0aef048bf8ef9f46c5.tar.gz |
gtk overrides: Fix template hierarchy issue
When a widget is inside a template it is created through a
g_object_new and does not have a python wrapper when
pygobject__g_instance_init is called. In that case, a wrapper is
created and the "__init__" method is called to instantiate it. Then,
"init_template" is called to init its own template (if it exists).
However, "init_template" needs to be called before the object
constructor in order to create and instantiate all its children,
signals and properties.
This issue is fixed by calling init_template before the contructor if
the python object has been created through g_object_new.
A new test for the template hierarchy is added (based on an example
from Marinus Schraal).
Closes: #257, #386
-rw-r--r-- | gi/gimodule.c | 13 | ||||
-rw-r--r-- | tests/test_gtk_template.py | 70 |
2 files changed, 79 insertions, 4 deletions
diff --git a/gi/gimodule.c b/gi/gimodule.c index f3404583..890a6bfa 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -1069,6 +1069,7 @@ pygobject__g_instance_init(GTypeInstance *instance, GObject *object = (GObject *) instance; PyObject *wrapper, *result; PyGILState_STATE state; + gboolean needs_init = FALSE; wrapper = g_object_get_qdata(object, pygobject_wrapper_key); if (wrapper == NULL) { @@ -1095,16 +1096,20 @@ pygobject__g_instance_init(GTypeInstance *instance, * will take the ref */ pygobject_ref_float ((PyGObject *) wrapper); - result = PyObject_CallMethod (wrapper, "__init__", NULL); + needs_init = TRUE; + } + + /* XXX: used for Gtk.Template */ + if (PyObject_HasAttrString ((PyObject*) Py_TYPE (wrapper), "__dontuse_ginstance_init__")) { + result = PyObject_CallMethod (wrapper, "__dontuse_ginstance_init__", NULL); if (result == NULL) PyErr_Print (); else Py_DECREF (result); } - /* XXX: used for Gtk.Template */ - if (PyObject_HasAttrString ((PyObject*) Py_TYPE (wrapper), "__dontuse_ginstance_init__")) { - result = PyObject_CallMethod (wrapper, "__dontuse_ginstance_init__", NULL); + if (needs_init) { + result = PyObject_CallMethod (wrapper, "__init__", NULL); if (result == NULL) PyErr_Print (); else diff --git a/tests/test_gtk_template.py b/tests/test_gtk_template.py index d3388b37..69911c81 100644 --- a/tests/test_gtk_template.py +++ b/tests/test_gtk_template.py @@ -586,3 +586,73 @@ def test_internal_child(): child = child.get_children()[0] assert isinstance(child, Gtk.Label) assert child.props.label == "foo" + + +def test_template_hierarchy(): + testlabel = """ + <interface> + <template class="TestLabel" parent="GtkLabel"> + </template> + </interface> + """ + @Gtk.Template(string=testlabel) + class TestLabel(Gtk.Label): + + __gtype_name__ = "TestLabel" + + def __init__(self): + super().__init__() + self.props.label = "TestLabel" + + testbox = """ + <interface> + <template class="TestBox" parent="GtkBox"> + <child> + <object class="TestLabel" id="_testlabel"/> + </child> + </template> + </interface> + """ + @Gtk.Template(string=testbox) + class TestBox(Gtk.Box): + + __gtype_name__ = "TestBox" + + _testlabel = Gtk.Template.Child() + + def __init__(self): + super().__init__() + + assert isinstance(self._testlabel, TestLabel) + + window = """ + <interface> + <template class="MyWindow" parent="GtkWindow"> + <property name="title">"Hellow World"</property> + <child> + <object class="TestBox" id="_testbox"> + <child> + <object class="TestLabel" id="_testlabel"/> + </child> + </object> + </child> + </template> + </interface> + """ + @Gtk.Template(string=window) + class MyWindow(Gtk.Window): + + __gtype_name__ = "MyWindow" + + _testbox = Gtk.Template.Child() + _testlabel = Gtk.Template.Child() + + def __init__(self): + super().__init__() + + assert isinstance(self._testbox, TestBox) + assert isinstance(self._testlabel, TestLabel) + assert len(self._testbox.get_children()) == 2 + + win = MyWindow() + assert isinstance(win, MyWindow) |