[gjs: 1/2] Gtk Templates: support connectObj argument



commit 6c060bf5d9b36f85e5601d4772f750cb509ba625
Author: Andy Holmes <andrew g r holmes gmail com>
Date:   Tue Nov 19 20:28:07 2019 -0800

    Gtk Templates: support connectObj argument
    
    This allows a template file to define `object` in signal handlers which
    will be passed to `Function.prototype.bind()` when connecting a handler.

 installed-tests/js/complex.ui       |  1 +
 installed-tests/js/testGtk.js       | 18 ++++++++++++++++++
 installed-tests/js/testLegacyGtk.js |  1 +
 modules/overrides/Gtk.js            | 10 +++++-----
 4 files changed, 25 insertions(+), 5 deletions(-)
---
diff --git a/installed-tests/js/complex.ui b/installed-tests/js/complex.ui
index 4096a4ad..b5136fbc 100644
--- a/installed-tests/js/complex.ui
+++ b/installed-tests/js/complex.ui
@@ -17,6 +17,7 @@
       <object class="GtkLabel" id="label-child2">
         <property name="label">Complex as well!</property>
         <property name="visible">True</property>
+        <signal name="grab-focus" handler="boundCallback" object="label-child" swapped="no"/>
       </object>
     </child>
     <child>
diff --git a/installed-tests/js/testGtk.js b/installed-tests/js/testGtk.js
index 475526f5..c7200c27 100644
--- a/installed-tests/js/testGtk.js
+++ b/installed-tests/js/testGtk.js
@@ -25,6 +25,7 @@ function createTemplate(className) {
       <object class="GtkLabel" id="label-child2">
         <property name="label">Complex as well!</property>
         <property name="visible">True</property>
+        <signal name="grab-focus" handler="boundCallback" object="label-child" swapped="no"/>
       </object>
     </child>
     <child>
@@ -46,6 +47,10 @@ const MyComplexGtkSubclass = GObject.registerClass({
     templateCallback(widget) {
         this.callbackEmittedBy = widget;
     }
+
+    boundCallback(widget) {
+        widget.callbackBoundTo = this;
+    }
 });
 
 // Sadly, putting this in the body of the class will prevent calling
@@ -73,6 +78,10 @@ const MyComplexGtkSubclassFromResource = GObject.registerClass({
     templateCallback(widget) {
         this.callbackEmittedBy = widget;
     }
+
+    boundCallback(widget) {
+        widget.callbackBoundTo = this;
+    }
 });
 
 const [templateFile, stream] = Gio.File.new_tmp(null);
@@ -95,6 +104,10 @@ const MyComplexGtkSubclassFromFile = GObject.registerClass({
     templateCallback(widget) {
         this.callbackEmittedBy = widget;
     }
+
+    boundCallback(widget) {
+        widget.callbackBoundTo = this;
+    }
 });
 
 const SubclassSubclass = GObject.registerClass(
@@ -108,6 +121,7 @@ function validateTemplate(description, ClassName, pending = false) {
             win = new Gtk.Window({type: Gtk.WindowType.TOPLEVEL});
             content = new ClassName();
             content.label_child.emit('grab-focus');
+            content.label_child2.emit('grab-focus');
             win.add(content);
         });
 
@@ -129,6 +143,10 @@ function validateTemplate(description, ClassName, pending = false) {
             expect(content.callbackEmittedBy).toBe(content.label_child);
         });
 
+        it('binds template callbacks to the correct object', function () {
+            expect(content.label_child2.callbackBoundTo).toBe(content.label_child);
+        });
+
         afterEach(function () {
             win.destroy();
         });
diff --git a/installed-tests/js/testLegacyGtk.js b/installed-tests/js/testLegacyGtk.js
index b1dbe72e..21f861f0 100644
--- a/installed-tests/js/testLegacyGtk.js
+++ b/installed-tests/js/testLegacyGtk.js
@@ -67,6 +67,7 @@ const MyComplexGtkSubclassFromResource = new Lang.Class({
     },
 
     templateCallback() {},
+    boundCallback() {},
 });
 
 function validateTemplate(description, ClassName) {
diff --git a/modules/overrides/Gtk.js b/modules/overrides/Gtk.js
index 7d0fdacc..cfe52d53 100644
--- a/modules/overrides/Gtk.js
+++ b/modules/overrides/Gtk.js
@@ -45,17 +45,17 @@ function _init() {
     Gtk.Widget.prototype._init = function (params) {
         if (this.constructor[Gtk.template]) {
             Gtk.Widget.set_connect_func.call(this.constructor, (builder, obj, signalName, handlerName, 
connectObj, flags) => {
-                if (connectObj !== null) {
-                    throw new Error('Unsupported template signal attribute "object"');
-                } else if (flags & GObject.ConnectFlags.SWAPPED) {
+                connectObj = connectObj || this;
+
+                if (flags & GObject.ConnectFlags.SWAPPED) {
                     throw new Error('Unsupported template signal flag "swapped"');
                 } else if (typeof this[handlerName] === 'undefined') {
                     throw new Error(`A handler called ${handlerName} was not ` +
                         `defined for signal ${signalName} on ${this}`);
                 } else if (flags & GObject.ConnectFlags.AFTER) {
-                    obj.connect_after(signalName, this[handlerName].bind(this));
+                    obj.connect_after(signalName, this[handlerName].bind(connectObj));
                 } else {
-                    obj.connect(signalName, this[handlerName].bind(this));
+                    obj.connect(signalName, this[handlerName].bind(connectObj));
                 }
             });
         }


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