summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Felder <jfelder@src.gnome.org>2020-04-25 02:23:51 +0200
committerJean Felder <jfelder@src.gnome.org>2020-12-06 15:04:09 +0100
commita4880dbc4575fadc0e3a494ca1c3d5374818deb9 (patch)
tree82bf92f05eb03caf5d880be77ef98915de54cc17
parent9215e3a1327b63e9036c6a45def9654e1e5d58d6 (diff)
downloadpygobject-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.py42
-rw-r--r--gi/pygi-struct-marshal.c36
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) {