diff options
author | Jean Felder <jfelder@src.gnome.org> | 2020-04-25 02:23:51 +0200 |
---|---|---|
committer | Jean Felder <jfelder@src.gnome.org> | 2020-12-06 15:04:09 +0100 |
commit | a4880dbc4575fadc0e3a494ca1c3d5374818deb9 (patch) | |
tree | 82bf92f05eb03caf5d880be77ef98915de54cc17 | |
parent | 9215e3a1327b63e9036c6a45def9654e1e5d58d6 (diff) | |
download | pygobject-a4880dbc4575fadc0e3a494ca1c3d5374818deb9.tar.gz |
Gtk.Template: Fix template support for GTK4
Gtk.Widget.set_connect_func() does not exist anymore and signals are
automatically connected. Instead, a GtkBuilderScope needs to be used
to create GtkBuilder's closure functions.
pygobject closure support is extended to support
functools.partial. This is used to create a GtkBuilder closure
function with an object different from the current object.
See MR https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1204 and
https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1230
Closes: #380
-rw-r--r-- | gi/_gtktemplate.py | 42 | ||||
-rw-r--r-- | gi/pygi-struct-marshal.c | 36 |
2 files changed, 74 insertions, 4 deletions
diff --git a/gi/_gtktemplate.py b/gi/_gtktemplate.py index 4b80106c..15f6b2c5 100644 --- a/gi/_gtktemplate.py +++ b/gi/_gtktemplate.py @@ -17,9 +17,43 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA +from functools import partial + from gi.repository import GLib, GObject, Gio +def define_builder_scope(): + from gi.repository import Gtk + + class BuilderScope(GObject.GObject, Gtk.BuilderScope): + + def __init__(self): + super().__init__() + + def do_create_closure(self, builder, func_name, flags, obj): + current_object = builder.get_current_object() + + if func_name not in current_object.__gtktemplate_methods__: + return None + + current_object.__gtktemplate_handlers__.add(func_name) + + swapped = int(flags & Gtk.BuilderClosureFlags.SWAPPED) + if swapped: + raise RuntimeError( + "%r not supported" % GObject.ConnectFlags.SWAPPED) + return None + + handler_name = current_object.__gtktemplate_methods__[func_name] + handler = getattr(current_object, handler_name) + if obj: + return partial(handler, swap_data=obj) + + return handler + + return BuilderScope + + def connect_func(builder, obj, signal_name, handler_name, connect_object, flags, cls): @@ -52,6 +86,8 @@ def connect_func(builder, obj, signal_name, handler_name, def register_template(cls): + from gi.repository import Gtk + bound_methods = {} bound_widgets = {} @@ -88,7 +124,11 @@ def register_template(cls): cls.__gtktemplate_methods__ = bound_methods cls.__gtktemplate_widgets__ = bound_widgets - cls.set_connect_func(connect_func, cls) + if Gtk._version == "4.0": + BuilderScope = define_builder_scope() + cls.set_template_scope(BuilderScope()) + else: + cls.set_connect_func(connect_func, cls) base_init_template = cls.init_template cls.__dontuse_ginstance_init__ = \ diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c index 6daf317c..13715888 100644 --- a/gi/pygi-struct-marshal.c +++ b/gi/pygi-struct-marshal.c @@ -182,9 +182,39 @@ pygi_arg_gclosure_from_py_marshal (PyObject *py_arg, g_closure_ref (closure); } } else { - closure = pyg_closure_new (py_arg, NULL, NULL); - g_closure_ref (closure); - g_closure_sink (closure); + PyObject *functools; + PyObject *partial = NULL; + + functools = PyImport_ImportModule ("functools"); + if (functools) { + partial = PyObject_GetAttrString (functools, "partial"); + Py_DECREF (functools); + } + + if (partial && PyObject_IsInstance (py_arg, partial) > 0) { + PyObject *partial_func; + PyObject *partial_keywords; + PyObject *swap_data; + + partial_func = PyObject_GetAttrString (py_arg, "func"); + partial_keywords = PyObject_GetAttrString (py_arg, "keywords"); + swap_data = PyDict_GetItemString (partial_keywords, "swap_data"); + + closure = pyg_closure_new (partial_func, NULL, swap_data); + + Py_DECREF (partial_func); + Py_DECREF (partial_keywords); + g_closure_ref (closure); + g_closure_sink (closure); + } else { + closure = pyg_closure_new (py_arg, NULL, NULL); + g_closure_ref (closure); + g_closure_sink (closure); + } + + if (partial) { + Py_DECREF (partial); + } } if (closure == NULL) { |