[pygobject/wip/jfelder/template-gtk4: 2/8] Gtk.Template: Fix template support for GTK4




commit 3243851528ad71f7d7f814bb81aafda1f75a25ff
Author: Jean Felder <jfelder src gnome org>
Date:   Sat Apr 25 02:23:51 2020 +0200

    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

 gi/_gtktemplate.py       | 42 +++++++++++++++++++++++++++++++++++++++++-
 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) {


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